(function() {
	UEDITOR_CONFIG = window.UEDITOR_CONFIG || {};
	var baidu = window.baidu || {};
	window.baidu = baidu;
	window.UE = baidu.editor = {
		plugins: {},
		commands: {},
		instants: {},
		I18N: {},
		_customizeUI: {},
		version: "3.9.0",
		constants: {
			STATEFUL: {
				DISABLED: -1,
				OFF: 0,
				ON: 1
			}
		}
	};
	var dom = UE.dom = {};
	var browser = UE.browser = function() {
		var agent = navigator.userAgent.toLowerCase(),
			opera = window.opera,
			browser = {
				ie: /(msie\s|trident.*rv:)([\w.]+)/i.test(agent),
				opera: !!opera && opera.version,
				webkit: agent.indexOf(" applewebkit/") > -1,
				mac: agent.indexOf("macintosh") > -1,
				quirks: document.compatMode == "BackCompat"
			};
		browser.gecko = navigator.product == "Gecko" && !browser.webkit && !browser.opera && !browser.ie;
		var version = 0;
		if (browser.ie) {
			var v1 = agent.match(/(?:msie\s([\w.]+))/);
			var v2 = agent.match(/(?:trident.*rv:([\w.]+))/);
			if (v1 && v2 && v1[1] && v2[1]) {
				version = Math.max(v1[1] * 1, v2[1] * 1)
			} else if (v1 && v1[1]) {
				version = v1[1] * 1
			} else if (v2 && v2[1]) {
				version = v2[1] * 1
			} else {
				version = 0
			}
			browser.ie11Compat = document.documentMode == 11;
			browser.ie9Compat = document.documentMode == 9;
			browser.ie8 = !!document.documentMode;
			browser.ie8Compat = document.documentMode == 8;
			browser.ie7Compat = version == 7 && !document.documentMode || document.documentMode == 7;
			browser.ie6Compat = version < 7 || browser.quirks;
			browser.ie9above = version > 8;
			browser.ie9below = version < 9;
			browser.ie11above = version > 10;
			browser.ie11below = version < 11
		}
		if (browser.gecko) {
			var geckoRelease = agent.match(/rv:([\d\.]+)/);
			if (geckoRelease) {
				geckoRelease = geckoRelease[1].split(".");
				version = geckoRelease[0] * 1e4 + (geckoRelease[1] || 0) * 100 + (geckoRelease[2] || 0) * 1
			}
		}
		if (/chrome\/(\d+\.\d)/i.test(agent)) {
			browser.chrome = +RegExp["$1"]
		}
		if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)) {
			browser.safari = +(RegExp["$1"] || RegExp["$2"])
		}
		if (browser.opera) version = parseFloat(opera.version());
		if (browser.webkit) version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]);
		browser.version = version;
		browser.isCompatible = !browser.mobile && (browser.ie && version >= 6 || browser.gecko && version >=
			10801 || browser.opera && version >= 9.5 || browser.air && version >= 1 || browser.webkit &&
			version >= 522 || false);
		return browser
	}();
	var ie = browser.ie,
		webkit = browser.webkit,
		gecko = browser.gecko,
		opera = browser.opera;
	var utils = UE.utils = {
		each: function(obj, iterator, context) {
			if (obj == null) return;
			if (obj.length === +obj.length) {
				for (var i = 0, l = obj.length; i < l; i++) {
					if (iterator.call(context, obj[i], i, obj) === false) return false
				}
			} else {
				for (var key in obj) {
					if (obj.hasOwnProperty(key)) {
						if (iterator.call(context, obj[key], key, obj) === false) return false
					}
				}
			}
		},
		makeInstance: function(obj) {
			var noop = new Function;
			noop.prototype = obj;
			obj = new noop;
			noop.prototype = null;
			return obj
		},
		isObject: function(item) {
			return item && typeof item === "object" && !Array.isArray(item)
		},
		merge: function(target, source) {
			var output = Object.assign({}, target);
			if (this.isObject(target) && this.isObject(source)) {
				Object.keys(source).forEach(key => {
					if (this.isObject(source[key])) {
						if (!(key in target)) {
							Object.assign(output, {
								[key]: source[key]
							})
						} else {
							output[key] = this.merge(target[key], source[key])
						}
					} else {
						Object.assign(output, {
							[key]: source[key]
						})
					}
				})
			}
			return output
		},
		extend: function(t, s, b) {
			if (s) {
				for (var k in s) {
					if (!b || !t.hasOwnProperty(k)) {
						t[k] = s[k]
					}
				}
			}
			return t
		},
		extend2: function(t) {
			var a = arguments;
			for (var i = 1; i < a.length; i++) {
				var x = a[i];
				for (var k in x) {
					if (!t.hasOwnProperty(k)) {
						t[k] = x[k]
					}
				}
			}
			return t
		},
		inherits: function(subClass, superClass) {
			var oldP = subClass.prototype,
				newP = utils.makeInstance(superClass.prototype);
			utils.extend(newP, oldP, true);
			subClass.prototype = newP;
			return newP.constructor = subClass
		},
		bind: function(fn, context) {
			return function() {
				return fn.apply(context, arguments)
			}
		},
		defer: function(fn, delay, exclusion) {
			var timerID;
			return function() {
				if (exclusion) {
					clearTimeout(timerID)
				}
				timerID = setTimeout(fn, delay)
			}
		},
		indexOf: function(array, item, start) {
			var index = -1;
			start = this.isNumber(start) ? start : 0;
			this.each(array, function(v, i) {
				if (i >= start && v === item) {
					index = i;
					return false
				}
			});
			return index
		},
		removeItem: function(array, item) {
			for (var i = 0, l = array.length; i < l; i++) {
				if (array[i] === item) {
					array.splice(i, 1);
					i--
				}
			}
		},
		trim: function(str) {
			return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, "")
		},
		listToMap: function(list) {
			if (!list) return {};
			list = utils.isArray(list) ? list : list.split(",");
			for (var i = 0, ci, obj = {}; ci = list[i++];) {
				obj[ci.toUpperCase()] = obj[ci] = 1
			}
			return obj
		},
		unhtml: function(str, reg) {
			return str ? str.replace(reg || /[&<">'](?:(amp|lt|ldquo|rdquo|quot|gt|#39|nbsp|#\d+);)?/g,
				function(a, b) {
					if (b) {
						return a
					} else {
						return {
							"<": "&lt;",
							"&": "&amp;",
							'"': "&quot;",
							"“": "&ldquo;",
							"”": "&rdquo;",
							">": "&gt;",
							"'": "&#39;"
						} [a]
					}
				}) : ""
		},
		html: function(str) {
			return str ? str.replace(/&((g|l|quo|ldquo|rdquo)t|amp|#39|nbsp);/g, function(m) {
				return {
					"&lt;": "<",
					"&amp;": "&",
					"&quot;": '"',
					"&ldquo;": "“",
					"&rdquo;": "”",
					"&gt;": ">",
					"&#39;": "'",
					"&nbsp;": " "
				} [m]
			}) : ""
		},
		cssStyleToDomStyle: function() {
			var test = document.createElement("div").style,
				cache = {
					float: test.cssFloat !== undefined ? "cssFloat" : test.styleFloat !== undefined ?
						"styleFloat" : "float"
				};
			return function(cssName) {
				return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g,
					function(match) {
						return match.charAt(1).toUpperCase()
					}))
			}
		}(),
		loadFile: function() {
			var tmpList = [];

			function getItem(doc, obj) {
				try {
					for (var i = 0, ci; ci = tmpList[i++];) {
						if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
							return ci
						}
					}
				} catch (e) {
					return null
				}
			}
			return function(doc, obj, fn) {
				var item = getItem(doc, obj);
				if (item) {
					if (item.ready) {
						fn && fn()
					} else {
						item.funs.push(fn)
					}
					return
				}
				tmpList.push({
					doc: doc,
					url: obj.src || obj.href,
					funs: [fn]
				});
				if (!doc.body) {
					var html = [];
					for (var p in obj) {
						if (p == "tag") continue;
						html.push(p + '="' + obj[p] + '"')
					}
					doc.write("<" + obj.tag + " " + html.join(" ") + " ></" + obj.tag + ">");
					return
				}
				if (obj.id && doc.getElementById(obj.id)) {
					return
				}
				var element = doc.createElement(obj.tag);
				delete obj.tag;
				for (var p in obj) {
					element.setAttribute(p, obj[p])
				}
				element.onload = element.onreadystatechange = function() {
					if (!this.readyState || /loaded|complete/.test(this.readyState)) {
						item = getItem(doc, obj);
						if (item.funs.length > 0) {
							item.ready = 1;
							for (var fi; fi = item.funs.pop();) {
								fi()
							}
						}
						element.onload = element.onreadystatechange = null
					}
				};
				element.onerror = function() {
					throw Error("The load " + (obj.href || obj.src) +
						" fails,check the url settings of file ueditor.config.js ")
				};
				doc.getElementsByTagName("head")[0].appendChild(element)
			}
		}(),
		isEmptyObject: function(obj) {
			if (obj == null) return true;
			if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
			for (var key in obj)
				if (obj.hasOwnProperty(key)) return false;
			return true
		},
		fixColor: function(name, value) {
			if (/color/i.test(name) && /rgba?/.test(value)) {
				var array = value.split(",");
				if (array.length > 3) return "";
				value = "#";
				for (var i = 0, color; color = array[i++];) {
					color = parseInt(color.replace(/[^\d]/gi, ""), 10).toString(16);
					value += color.length == 1 ? "0" + color : color
				}
				value = value.toUpperCase()
			}
			return value
		},
		optCss: function(val) {
			var padding, margin, border;
			val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi, function(str, key, name,
			val) {
				if (val.split(" ").length == 1) {
					switch (key) {
						case "padding":
							!padding && (padding = {});
							padding[name] = val;
							return "";
						case "margin":
							!margin && (margin = {});
							margin[name] = val;
							return "";
						case "border":
							return val == "initial" ? "" : str
					}
				}
				return str
			});

			function opt(obj, name) {
				if (!obj) {
					return ""
				}
				var t = obj.top,
					b = obj.bottom,
					l = obj.left,
					r = obj.right,
					val = "";
				if (!t || !l || !b || !r) {
					for (var p in obj) {
						val += ";" + name + "-" + p + ":" + obj[p] + ";"
					}
				} else {
					val += ";" + name + ":" + (t == b && b == l && l == r ? t : t == b && l == r ? t + " " +
						l : l == r ? t + " " + l + " " + b : t + " " + r + " " + b + " " + l) + ";"
				}
				return val
			}
			val += opt(padding, "padding") + opt(margin, "margin");
			return val.replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, "").replace(/;([ \n\r\t]+)|\1;/g, ";").replace(
				/(&((l|g)t|quot|#39))?;{2,}/g,
				function(a, b) {
					return b ? b + ";;" : ";"
				})
		},
		clone: function(source, target) {
			var tmp;
			target = target || {};
			for (var i in source) {
				if (source.hasOwnProperty(i)) {
					tmp = source[i];
					if (typeof tmp == "object") {
						target[i] = utils.isArray(tmp) ? [] : {};
						utils.clone(source[i], target[i])
					} else {
						target[i] = tmp
					}
				}
			}
			return target
		},
		transUnitToPx: function(val) {
			if (!/(pt|cm)/.test(val)) {
				return val
			}
			var unit;
			val.replace(/([\d.]+)(\w+)/, function(str, v, u) {
				val = v;
				unit = u
			});
			switch (unit) {
				case "cm":
					val = parseFloat(val) * 25;
					break;
				case "pt":
					val = Math.round(parseFloat(val) * 96 / 72)
			}
			return val + (val ? "px" : "")
		},
		domReady: function() {
			var fnArr = [];

			function doReady(doc) {
				doc.isReady = true;
				for (var ci; ci = fnArr.pop(); ci()) {}
			}
			return function(onready, win) {
				win = win || window;
				var doc = win.document;
				onready && fnArr.push(onready);
				if (doc.readyState === "complete") {
					doReady(doc)
				} else {
					doc.isReady && doReady(doc);
					if (browser.ie && browser.version != 11) {
						(function() {
							if (doc.isReady) return;
							try {
								doc.documentElement.doScroll("left")
							} catch (error) {
								setTimeout(arguments.callee, 0);
								return
							}
							doReady(doc)
						})();
						win.attachEvent("onload", function() {
							doReady(doc)
						})
					} else {
						doc.addEventListener("DOMContentLoaded", function() {
							doc.removeEventListener("DOMContentLoaded", arguments.callee,
							false);
							doReady(doc)
						}, false);
						win.addEventListener("load", function() {
							doReady(doc)
						}, false)
					}
				}
			}
		}(),
		cssRule: browser.ie && browser.version != 11 ? function(key, style, doc) {
			var indexList, index;
			if (style === undefined || style && style.nodeType && style.nodeType == 9) {
				doc = style && style.nodeType && style.nodeType == 9 ? style : doc || document;
				indexList = doc.indexList || (doc.indexList = {});
				index = indexList[key];
				if (index !== undefined) {
					return doc.styleSheets[index].cssText
				}
				return undefined
			}
			doc = doc || document;
			indexList = doc.indexList || (doc.indexList = {});
			index = indexList[key];
			if (style === "") {
				if (index !== undefined) {
					doc.styleSheets[index].cssText = "";
					delete indexList[key];
					return true
				}
				return false
			}
			if (index !== undefined) {
				sheetStyle = doc.styleSheets[index]
			} else {
				sheetStyle = doc.createStyleSheet("", index = doc.styleSheets.length);
				indexList[key] = index
			}
			sheetStyle.cssText = style
		} : function(key, style, doc) {
			var head, node;
			if (style === undefined || style && style.nodeType && style.nodeType == 9) {
				doc = style && style.nodeType && style.nodeType == 9 ? style : doc || document;
				node = doc.getElementById(key);
				return node ? node.innerHTML : undefined
			}
			doc = doc || document;
			node = doc.getElementById(key);
			if (style === "") {
				if (node) {
					node.parentNode.removeChild(node);
					return true
				}
				return false
			}
			if (node) {
				node.innerHTML = style
			} else {
				node = doc.createElement("style");
				node.id = key;
				node.innerHTML = style;
				doc.getElementsByTagName("head")[0].appendChild(node)
			}
		},
		sort: function(array, compareFn) {
			compareFn = compareFn || function(item1, item2) {
				return item1.localeCompare(item2)
			};
			for (var i = 0, len = array.length; i < len; i++) {
				for (var j = i, length = array.length; j < length; j++) {
					if (compareFn(array[i], array[j]) > 0) {
						var t = array[i];
						array[i] = array[j];
						array[j] = t
					}
				}
			}
			return array
		},
		serializeParam: function(json) {
			var strArr = [];
			for (var i in json) {
				if (i == "method" || i == "timeout" || i == "async") continue;
				if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() ==
						"object")) {
					strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]))
				} else if (utils.isArray(json[i])) {
					for (var j = 0; j < json[i].length; j++) {
						strArr.push(encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j]))
					}
				}
			}
			return strArr.join("&")
		},
		formatUrl: function(url) {
			var u = url.replace(/&&/g, "&");
			u = u.replace(/\?&/g, "?");
			u = u.replace(/&$/g, "");
			u = u.replace(/&#/g, "#");
			u = u.replace(/&+/g, "&");
			return u
		},
		addStyleContent: function(cssContent) {
			var style = document.createElement("style");
			style.innerHTML = cssContent;
			document.head.appendChild(style)
		},
		isCrossDomainUrl: function(url) {
			var a = document.createElement("a");
			a.href = url;
			if (browser.ie) {
				a.href = a.href
			}
			return !(a.protocol == location.protocol && a.hostname == location.hostname && (a.port ==
				location.port || a.port == "80" && location.port == "" || a.port == "" && location
				.port == "80"))
		},
		clearEmptyAttrs: function(obj) {
			for (var p in obj) {
				if (obj[p] === "") {
					delete obj[p]
				}
			}
			return obj
		},
		str2json: function(s) {
			if (!utils.isString(s)) return null;
			if (window.JSON) {
				return JSON.parse(s)
			} else {
				return new Function("return " + utils.trim(s || ""))()
			}
		},
		json2str: function() {
			if (window.JSON) {
				return JSON.stringify
			} else {
				var escapeMap = {
					"\b": "\\b",
					"\t": "\\t",
					"\n": "\\n",
					"\f": "\\f",
					"\r": "\\r",
					'"': '\\"',
					"\\": "\\\\"
				};

				function encodeString(source) {
					if (/["\\\x00-\x1f]/.test(source)) {
						source = source.replace(/["\\\x00-\x1f]/g, function(match) {
							var c = escapeMap[match];
							if (c) {
								return c
							}
							c = match.charCodeAt();
							return "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16)
						})
					}
					return '"' + source + '"'
				}

				function encodeArray(source) {
					var result = ["["],
						l = source.length,
						preComma, i, item;
					for (i = 0; i < l; i++) {
						item = source[i];
						switch (typeof item) {
							case "undefined":
							case "function":
							case "unknown":
								break;
							default:
								if (preComma) {
									result.push(",")
								}
								result.push(utils.json2str(item));
								preComma = 1
						}
					}
					result.push("]");
					return result.join("")
				}

				function pad(source) {
					return source < 10 ? "0" + source : source
				}

				function encodeDate(source) {
					return '"' + source.getFullYear() + "-" + pad(source.getMonth() + 1) + "-" + pad(source
							.getDate()) + "T" + pad(source.getHours()) + ":" + pad(source.getMinutes()) +
						":" + pad(source.getSeconds()) + '"'
				}
				return function(value) {
					switch (typeof value) {
						case "undefined":
							return "undefined";
						case "number":
							return isFinite(value) ? String(value) : "null";
						case "string":
							return encodeString(value);
						case "boolean":
							return String(value);
						default:
							if (value === null) {
								return "null"
							} else if (utils.isArray(value)) {
								return encodeArray(value)
							} else if (utils.isDate(value)) {
								return encodeDate(value)
							} else {
								var result = ["{"],
									encode = utils.json2str,
									preComma, item;
								for (var key in value) {
									if (Object.prototype.hasOwnProperty.call(value, key)) {
										item = value[key];
										switch (typeof item) {
											case "undefined":
											case "unknown":
											case "function":
												break;
											default:
												if (preComma) {
													result.push(",")
												}
												preComma = 1;
												result.push(encode(key) + ":" + encode(item))
										}
									}
								}
								result.push("}");
								return result.join("")
							}
					}
				}
			}
		}()
	};
	utils.each(["String", "Function", "Array", "Number", "RegExp", "Object", "Date"], function(v) {
		UE.utils["is" + v] = function(obj) {
			return Object.prototype.toString.apply(obj) == "[object " + v + "]"
		}
	});
	var EventBase = UE.EventBase = function() {};
	EventBase.prototype = {
		addListener: function(types, listener) {
			types = utils.trim(types).split(/\s+/);
			for (var i = 0, ti; ti = types[i++];) {
				getListener(this, ti, true).push(listener)
			}
		},
		on: function(types, listener) {
			return this.addListener(types, listener)
		},
		off: function(types, listener) {
			return this.removeListener(types, listener)
		},
		trigger: function() {
			return this.fireEvent.apply(this, arguments)
		},
		removeListener: function(types, listener) {
			types = utils.trim(types).split(/\s+/);
			for (var i = 0, ti; ti = types[i++];) {
				utils.removeItem(getListener(this, ti) || [], listener)
			}
		},
		fireEvent: function() {
			var types = arguments[0];
			types = utils.trim(types).split(" ");
			for (var i = 0, ti; ti = types[i++];) {
				var listeners = getListener(this, ti),
					r, t, k;
				if (listeners) {
					k = listeners.length;
					while (k--) {
						if (!listeners[k]) continue;
						t = listeners[k].apply(this, arguments);
						if (t === true) {
							return t
						}
						if (t !== undefined) {
							r = t
						}
					}
				}
				if (t = this["on" + ti.toLowerCase()]) {
					r = t.apply(this, arguments)
				}
			}
			return r
		}
	};

	function getListener(obj, type, force) {
		var allListeners;
		type = type.toLowerCase();
		return (allListeners = obj.__allListeners || force && (obj.__allListeners = {})) && (allListeners[type] ||
			force && (allListeners[type] = []))
	}
	var dtd = dom.dtd = function() {
		function _(s) {
			for (var k in s) {
				s[k.toUpperCase()] = s[k]
			}
			return s
		}
		var X = utils.extend2;
		var A = _({
				isindex: 1,
				fieldset: 1
			}),
			B = _({
				input: 1,
				button: 1,
				select: 1,
				textarea: 1,
				label: 1
			}),
			C = X(_({
				a: 1
			}), B),
			D = X({
				iframe: 1
			}, C),
			E = _({
				hr: 1,
				ul: 1,
				menu: 1,
				div: 1,
				blockquote: 1,
				noscript: 1,
				table: 1,
				center: 1,
				address: 1,
				dir: 1,
				pre: 1,
				h5: 1,
				dl: 1,
				h4: 1,
				noframes: 1,
				h6: 1,
				ol: 1,
				h1: 1,
				h3: 1,
				h2: 1
			}),
			F = _({
				ins: 1,
				del: 1,
				script: 1,
				style: 1
			}),
			G = X(_({
				mark: 1,
				b: 1,
				acronym: 1,
				bdo: 1,
				var: 1,
				"#": 1,
				abbr: 1,
				code: 1,
				br: 1,
				i: 1,
				cite: 1,
				kbd: 1,
				u: 1,
				strike: 1,
				s: 1,
				tt: 1,
				strong: 1,
				q: 1,
				samp: 1,
				em: 1,
				dfn: 1,
				span: 1
			}), F),
			H = X(_({
				sub: 1,
				img: 1,
				embed: 1,
				object: 1,
				sup: 1,
				basefont: 1,
				map: 1,
				applet: 1,
				font: 1,
				big: 1,
				small: 1
			}), G),
			I = X(_({
				p: 1
			}), H),
			J = X(_({
				iframe: 1
			}), H, B),
			K = _({
				img: 1,
				embed: 1,
				noscript: 1,
				br: 1,
				kbd: 1,
				center: 1,
				button: 1,
				basefont: 1,
				h5: 1,
				h4: 1,
				samp: 1,
				h6: 1,
				ol: 1,
				h1: 1,
				h3: 1,
				h2: 1,
				form: 1,
				font: 1,
				"#": 1,
				select: 1,
				menu: 1,
				ins: 1,
				abbr: 1,
				label: 1,
				code: 1,
				table: 1,
				script: 1,
				cite: 1,
				input: 1,
				iframe: 1,
				strong: 1,
				textarea: 1,
				noframes: 1,
				big: 1,
				small: 1,
				span: 1,
				hr: 1,
				sub: 1,
				bdo: 1,
				var: 1,
				div: 1,
				object: 1,
				sup: 1,
				strike: 1,
				dir: 1,
				map: 1,
				dl: 1,
				applet: 1,
				del: 1,
				isindex: 1,
				fieldset: 1,
				ul: 1,
				b: 1,
				acronym: 1,
				a: 1,
				blockquote: 1,
				i: 1,
				u: 1,
				s: 1,
				tt: 1,
				address: 1,
				q: 1,
				pre: 1,
				p: 1,
				em: 1,
				dfn: 1
			}),
			L = X(_({
				a: 0
			}), J),
			M = _({
				tr: 1
			}),
			N = _({
				"#": 1
			}),
			O = X(_({
				param: 1
			}), K),
			P = X(_({
				form: 1
			}), A, D, E, I),
			Q = _({
				li: 1,
				ol: 1,
				ul: 1
			}),
			R = _({
				style: 1,
				script: 1
			}),
			S = _({
				base: 1,
				link: 1,
				meta: 1,
				title: 1
			}),
			T = X(S, R),
			U = _({
				head: 1,
				body: 1
			}),
			V = _({
				html: 1
			});
		var block = _({
				address: 1,
				blockquote: 1,
				center: 1,
				dir: 1,
				div: 1,
				dl: 1,
				fieldset: 1,
				form: 1,
				h1: 1,
				h2: 1,
				h3: 1,
				h4: 1,
				h5: 1,
				h6: 1,
				hr: 1,
				isindex: 1,
				menu: 1,
				noframes: 1,
				ol: 1,
				p: 1,
				pre: 1,
				table: 1,
				ul: 1
			}),
			empty = _({
				area: 1,
				base: 1,
				basefont: 1,
				br: 1,
				col: 1,
				command: 1,
				dialog: 1,
				embed: 1,
				hr: 1,
				img: 1,
				input: 1,
				isindex: 1,
				keygen: 1,
				link: 1,
				meta: 1,
				param: 1,
				source: 1,
				track: 1,
				wbr: 1
			});
		return _({
			$nonBodyContent: X(V, U, S),
			$block: block,
			$inline: L,
			$inlineWithA: X(_({
				a: 1
			}), L),
			$body: X(_({
				script: 1,
				style: 1
			}), block),
			$cdata: _({
				script: 1,
				style: 1
			}),
			$empty: empty,
			$nonChild: _({
				iframe: 1,
				textarea: 1
			}),
			$listItem: _({
				dd: 1,
				dt: 1,
				li: 1
			}),
			$list: _({
				ul: 1,
				ol: 1,
				dl: 1
			}),
			$isNotEmpty: _({
				table: 1,
				ul: 1,
				ol: 1,
				dl: 1,
				iframe: 1,
				area: 1,
				base: 1,
				col: 1,
				hr: 1,
				img: 1,
				embed: 1,
				input: 1,
				textarea: 1,
				link: 1,
				meta: 1,
				param: 1,
				h1: 1,
				h2: 1,
				h3: 1,
				h4: 1,
				h5: 1,
				h6: 1
			}),
			$removeEmpty: _({
				a: 1,
				abbr: 1,
				acronym: 1,
				address: 1,
				b: 1,
				bdo: 1,
				big: 1,
				cite: 1,
				code: 1,
				del: 1,
				dfn: 1,
				em: 1,
				font: 1,
				i: 1,
				ins: 1,
				label: 1,
				kbd: 1,
				q: 1,
				s: 1,
				samp: 1,
				small: 1,
				span: 1,
				strike: 1,
				strong: 1,
				sub: 1,
				sup: 1,
				tt: 1,
				u: 1,
				var: 1
			}),
			$removeEmptyBlock: _({
				p: 1,
				div: 1
			}),
			$tableContent: _({
				caption: 1,
				col: 1,
				colgroup: 1,
				tbody: 1,
				td: 1,
				tfoot: 1,
				th: 1,
				thead: 1,
				tr: 1,
				table: 1
			}),
			$notTransContent: _({
				pre: 1,
				script: 1,
				style: 1,
				textarea: 1
			}),
			html: U,
			head: T,
			style: N,
			script: N,
			body: P,
			base: {},
			link: {},
			meta: {},
			title: N,
			col: {},
			tr: _({
				td: 1,
				th: 1
			}),
			img: {},
			embed: {},
			colgroup: _({
				thead: 1,
				col: 1,
				tbody: 1,
				tr: 1,
				tfoot: 1
			}),
			noscript: P,
			td: P,
			br: {},
			th: P,
			center: P,
			kbd: L,
			button: X(I, E),
			basefont: {},
			h5: L,
			h4: L,
			samp: L,
			h6: L,
			ol: Q,
			h1: L,
			h3: L,
			option: N,
			h2: L,
			form: X(A, D, E, I),
			select: _({
				optgroup: 1,
				option: 1
			}),
			font: L,
			ins: L,
			menu: Q,
			abbr: L,
			label: L,
			table: _({
				thead: 1,
				col: 1,
				tbody: 1,
				tr: 1,
				colgroup: 1,
				caption: 1,
				tfoot: 1
			}),
			code: L,
			tfoot: M,
			cite: L,
			li: P,
			input: {},
			iframe: P,
			strong: L,
			textarea: N,
			noframes: P,
			big: L,
			small: L,
			span: _({
				"#": 1,
				br: 1,
				b: 1,
				strong: 1,
				u: 1,
				i: 1,
				em: 1,
				sub: 1,
				sup: 1,
				strike: 1,
				span: 1
			}),
			hr: L,
			dt: L,
			sub: L,
			optgroup: _({
				option: 1
			}),
			param: {},
			bdo: L,
			var: L,
			div: P,
			object: O,
			sup: L,
			dd: P,
			strike: L,
			area: {},
			dir: Q,
			map: X(_({
				area: 1,
				form: 1,
				p: 1
			}), A, F, E),
			applet: O,
			dl: _({
				dt: 1,
				dd: 1
			}),
			del: L,
			isindex: {},
			fieldset: X(_({
				legend: 1
			}), K),
			thead: M,
			ul: Q,
			acronym: L,
			b: L,
			a: X(_({
				a: 1
			}), J),
			blockquote: X(_({
				td: 1,
				tr: 1,
				tbody: 1,
				li: 1
			}), P),
			caption: L,
			i: L,
			u: L,
			tbody: M,
			s: L,
			address: X(D, I),
			tt: L,
			legend: L,
			q: L,
			pre: X(G, C),
			p: X(_({
				a: 1
			}), L),
			em: L,
			dfn: L,
			mark: L
		})
	}();

	function getDomNode(node, start, ltr, startFromChild, fn, guard) {
		var tmpNode = startFromChild && node[start],
			parent;
		!tmpNode && (tmpNode = node[ltr]);
		while (!tmpNode && (parent = (parent || node).parentNode)) {
			if (parent.tagName == "BODY" || guard && !guard(parent)) {
				return null
			}
			tmpNode = parent[ltr]
		}
		if (tmpNode && fn && !fn(tmpNode)) {
			return getDomNode(tmpNode, start, ltr, false, fn)
		}
		return tmpNode
	}
	var attrFix = ie && browser.version < 9 ? {
			tabindex: "tabIndex",
			readonly: "readOnly",
			for: "htmlFor",
			class: "className",
			maxlength: "maxLength",
			cellspacing: "cellSpacing",
			cellpadding: "cellPadding",
			rowspan: "rowSpan",
			colspan: "colSpan",
			usemap: "useMap",
			frameborder: "frameBorder"
		} : {
			tabindex: "tabIndex",
			readonly: "readOnly"
		},
		styleBlock = utils.listToMap(["-webkit-box", "-moz-box", "block", "list-item", "table", "table-row-group",
			"table-header-group", "table-footer-group", "table-row", "table-column-group", "table-column",
			"table-cell", "table-caption"
		]);
	var domUtils = dom.domUtils = {
		NODE_ELEMENT: 1,
		NODE_DOCUMENT: 9,
		NODE_TEXT: 3,
		NODE_COMMENT: 8,
		NODE_DOCUMENT_FRAGMENT: 11,
		POSITION_IDENTICAL: 0,
		POSITION_DISCONNECTED: 1,
		POSITION_FOLLOWING: 2,
		POSITION_PRECEDING: 4,
		POSITION_IS_CONTAINED: 8,
		POSITION_CONTAINS: 16,
		fillChar: ie && browser.version === "6" ? "\ufeff" : "​",
		keys: {
			8: 1,
			46: 1,
			16: 1,
			17: 1,
			18: 1,
			37: 1,
			38: 1,
			39: 1,
			40: 1,
			13: 1
		},
		getPosition: function(nodeA, nodeB) {
			if (nodeA === nodeB) {
				return 0
			}
			var node, parentsA = [nodeA],
				parentsB = [nodeB];
			node = nodeA;
			while (node = node.parentNode) {
				if (node === nodeB) {
					return 10
				}
				parentsA.push(node)
			}
			node = nodeB;
			while (node = node.parentNode) {
				if (node === nodeA) {
					return 20
				}
				parentsB.push(node)
			}
			parentsA.reverse();
			parentsB.reverse();
			if (parentsA[0] !== parentsB[0]) {
				return 1
			}
			var i = -1;
			while (i++, parentsA[i] === parentsB[i]) {}
			nodeA = parentsA[i];
			nodeB = parentsB[i];
			while (nodeA = nodeA.nextSibling) {
				if (nodeA === nodeB) {
					return 4
				}
			}
			return 2
		},
		getNodeIndex: function(node, ignoreTextNode) {
			var preNode = node,
				i = 0;
			while (preNode = preNode.previousSibling) {
				if (ignoreTextNode && preNode.nodeType == 3) {
					if (preNode.nodeType != preNode.nextSibling.nodeType) {
						i++
					}
					continue
				}
				i++
			}
			return i
		},
		inDoc: function(node, doc) {
			return domUtils.getPosition(node, doc) === 10
		},
		findParent: function(node, filterFn, includeSelf) {
			if (node && !domUtils.isBody(node)) {
				node = includeSelf ? node : node.parentNode;
				while (node) {
					if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
						return filterFn && !filterFn(node) && domUtils.isBody(node) ? null : node
					}
					node = node.parentNode
				}
			}
			return null
		},
		findParentByTagName: function(node, tagNames, includeSelf, excludeFn) {
			tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]);
			return domUtils.findParent(node, function(node) {
				return tagNames[node.tagName] && !(excludeFn && excludeFn(node))
			}, includeSelf)
		},
		findParents: function(node, includeSelf, filterFn, closerFirst) {
			var parents = includeSelf && (filterFn && filterFn(node) || !filterFn) ? [node] : [];
			while (node = domUtils.findParent(node, filterFn)) {
				parents.push(node)
			}
			return closerFirst ? parents : parents.reverse()
		},
		insertAfter: function(node, newNode) {
			return node.nextSibling ? node.parentNode.insertBefore(newNode, node.nextSibling) : node
				.parentNode.appendChild(newNode)
		},
		remove: function(node, keepChildren) {
			var parent = node.parentNode,
				child;
			if (parent) {
				if (keepChildren && node.hasChildNodes()) {
					while (child = node.firstChild) {
						parent.insertBefore(child, node)
					}
				}
				parent.removeChild(node)
			}
			return node
		},
		getNextDomNode: function(node, startFromChild, filterFn, guard) {
			return getDomNode(node, "firstChild", "nextSibling", startFromChild, filterFn, guard)
		},
		getPreDomNode: function(node, startFromChild, filterFn, guard) {
			return getDomNode(node, "lastChild", "previousSibling", startFromChild, filterFn, guard)
		},
		isBookmarkNode: function(node) {
			return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id)
		},
		getWindow: function(node) {
			var doc = node.ownerDocument || node;
			return doc.defaultView || doc.parentWindow
		},
		getCommonAncestor: function(nodeA, nodeB) {
			if (nodeA === nodeB) return nodeA;
			var parentsA = [nodeA],
				parentsB = [nodeB],
				parent = nodeA,
				i = -1;
			while (parent = parent.parentNode) {
				if (parent === nodeB) {
					return parent
				}
				parentsA.push(parent)
			}
			parent = nodeB;
			while (parent = parent.parentNode) {
				if (parent === nodeA) return parent;
				parentsB.push(parent)
			}
			parentsA.reverse();
			parentsB.reverse();
			while (i++, parentsA[i] === parentsB[i]) {}
			return i == 0 ? null : parentsA[i - 1]
		},
		clearEmptySibling: function(node, ignoreNext, ignorePre) {
			function clear(next, dir) {
				var tmpNode;
				while (next && !domUtils.isBookmarkNode(next) && (domUtils.isEmptyInlineElement(next) || !
						new RegExp("[^\t\n\r" + domUtils.fillChar + "]").test(next.nodeValue))) {
					tmpNode = next[dir];
					domUtils.remove(next);
					next = tmpNode
				}
			}!ignoreNext && clear(node.nextSibling, "nextSibling");
			!ignorePre && clear(node.previousSibling, "previousSibling")
		},
		split: function(node, offset) {
			var doc = node.ownerDocument;
			if (browser.ie && offset == node.nodeValue.length) {
				var next = doc.createTextNode("");
				return domUtils.insertAfter(node, next)
			}
			var retval = node.splitText(offset);
			if (browser.ie8) {
				var tmpNode = doc.createTextNode("");
				domUtils.insertAfter(retval, tmpNode);
				domUtils.remove(tmpNode)
			}
			return retval
		},
		isWhitespace: function(node) {
			return !new RegExp("[^ \t\n\r" + domUtils.fillChar + "]").test(node.nodeValue)
		},
		getXY: function(element) {
			var x = 0,
				y = 0;
			while (element.offsetParent) {
				y += element.offsetTop;
				x += element.offsetLeft;
				element = element.offsetParent
			}
			return {
				x: x,
				y: y
			}
		},
		on: function(element, type, handler) {
			var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
				k = types.length;
			if (k)
				while (k--) {
					type = types[k];
					if (element.addEventListener) {
						element.addEventListener(type, handler, false)
					} else {
						if (!handler._d) {
							handler._d = {
								els: []
							}
						}
						var key = type + handler.toString(),
							index = utils.indexOf(handler._d.els, element);
						if (!handler._d[key] || index == -1) {
							if (index == -1) {
								handler._d.els.push(element)
							}
							if (!handler._d[key]) {
								handler._d[key] = function(evt) {
									return handler.call(evt.srcElement, evt || window.event)
								}
							}
							element.attachEvent("on" + type, handler._d[key])
						}
					}
				}
			element = null
		},
		un: function(element, type, handler) {
			var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
				k = types.length;
			if (k)
				while (k--) {
					type = types[k];
					if (element.removeEventListener) {
						element.removeEventListener(type, handler, false)
					} else {
						var key = type + handler.toString();
						try {
							element.detachEvent("on" + type, handler._d ? handler._d[key] : handler)
						} catch (e) {}
						if (handler._d && handler._d[key]) {
							var index = utils.indexOf(handler._d.els, element);
							if (index != -1) {
								handler._d.els.splice(index, 1)
							}
							handler._d.els.length == 0 && delete handler._d[key]
						}
					}
				}
		},
		isSameElement: function(nodeA, nodeB) {
			if (nodeA.tagName != nodeB.tagName) {
				return false
			}
			var thisAttrs = nodeA.attributes,
				otherAttrs = nodeB.attributes;
			if (!ie && thisAttrs.length != otherAttrs.length) {
				return false
			}
			var attrA, attrB, al = 0,
				bl = 0;
			for (var i = 0; attrA = thisAttrs[i++];) {
				if (attrA.nodeName == "style") {
					if (attrA.specified) {
						al++
					}
					if (domUtils.isSameStyle(nodeA, nodeB)) {
						continue
					} else {
						return false
					}
				}
				if (ie) {
					if (attrA.specified) {
						al++;
						attrB = otherAttrs.getNamedItem(attrA.nodeName)
					} else {
						continue
					}
				} else {
					attrB = nodeB.attributes[attrA.nodeName]
				}
				if (!attrB.specified || attrA.nodeValue != attrB.nodeValue) {
					return false
				}
			}
			if (ie) {
				for (i = 0; attrB = otherAttrs[i++];) {
					if (attrB.specified) {
						bl++
					}
				}
				if (al != bl) {
					return false
				}
			}
			return true
		},
		isSameStyle: function(nodeA, nodeB) {
			var styleA = nodeA.style.cssText.replace(/( ?; ?)/g, ";").replace(/( ?: ?)/g, ":"),
				styleB = nodeB.style.cssText.replace(/( ?; ?)/g, ";").replace(/( ?: ?)/g, ":");
			if (browser.opera) {
				styleA = nodeA.style;
				styleB = nodeB.style;
				if (styleA.length != styleB.length) return false;
				for (var p in styleA) {
					if (/^(\d+|csstext)$/i.test(p)) {
						continue
					}
					if (styleA[p] != styleB[p]) {
						return false
					}
				}
				return true
			}
			if (!styleA || !styleB) {
				return styleA == styleB
			}
			styleA = styleA.split(";");
			styleB = styleB.split(";");
			if (styleA.length != styleB.length) {
				return false
			}
			for (var i = 0, ci; ci = styleA[i++];) {
				if (utils.indexOf(styleB, ci) == -1) {
					return false
				}
			}
			return true
		},
		isBlockElm: function(node) {
			return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(
				node, "display")]) && !dtd.$nonChild[node.tagName]
		},
		isBody: function(node) {
			return node && node.nodeType == 1 && node.tagName.toLowerCase() == "body"
		},
		breakParent: function(node, parent) {
			var tmpNode, parentClone = node,
				clone = node,
				leftNodes, rightNodes;
			do {
				parentClone = parentClone.parentNode;
				if (leftNodes) {
					tmpNode = parentClone.cloneNode(false);
					tmpNode.appendChild(leftNodes);
					leftNodes = tmpNode;
					tmpNode = parentClone.cloneNode(false);
					tmpNode.appendChild(rightNodes);
					rightNodes = tmpNode
				} else {
					leftNodes = parentClone.cloneNode(false);
					rightNodes = leftNodes.cloneNode(false)
				}
				while (tmpNode = clone.previousSibling) {
					leftNodes.insertBefore(tmpNode, leftNodes.firstChild)
				}
				while (tmpNode = clone.nextSibling) {
					rightNodes.appendChild(tmpNode)
				}
				clone = parentClone
			} while (parent !== parentClone);
			tmpNode = parent.parentNode;
			tmpNode.insertBefore(leftNodes, parent);
			tmpNode.insertBefore(rightNodes, parent);
			tmpNode.insertBefore(node, rightNodes);
			domUtils.remove(parent);
			return node
		},
		isEmptyInlineElement: function(node) {
			if (node.nodeType != 1 || !dtd.$removeEmpty[node.tagName]) {
				return 0
			}
			node = node.firstChild;
			while (node) {
				if (domUtils.isBookmarkNode(node)) {
					return 0
				}
				if (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node) || node.nodeType == 3 && !
					domUtils.isWhitespace(node)) {
					return 0
				}
				node = node.nextSibling
			}
			return 1
		},
		trimWhiteTextNode: function(node) {
			function remove(dir) {
				var child;
				while ((child = node[dir]) && child.nodeType == 3 && domUtils.isWhitespace(child)) {
					node.removeChild(child)
				}
			}
			remove("firstChild");
			remove("lastChild")
		},
		mergeChild: function(node, tagName, attrs) {
			var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase());
			for (var i = 0, ci; ci = list[i++];) {
				if (!ci.parentNode || domUtils.isBookmarkNode(ci)) {
					continue
				}
				if (ci.tagName.toLowerCase() == "span") {
					if (node === ci.parentNode) {
						domUtils.trimWhiteTextNode(node);
						if (node.childNodes.length == 1) {
							node.style.cssText = ci.style.cssText + ";" + node.style.cssText;
							domUtils.remove(ci, true);
							continue
						}
					}
					ci.style.cssText = node.style.cssText + ";" + ci.style.cssText;
					if (attrs) {
						var style = attrs.style;
						if (style) {
							style = style.split(";");
							for (var j = 0, s; s = style[j++];) {
								ci.style[utils.cssStyleToDomStyle(s.split(":")[0])] = s.split(":")[1]
							}
						}
					}
					if (domUtils.isSameStyle(ci, node)) {
						domUtils.remove(ci, true)
					}
					continue
				}
				if (domUtils.isSameElement(node, ci)) {
					domUtils.remove(ci, true)
				}
			}
		},
		getElementsByTagName: function(node, tagName, filter) {
			if (filter && utils.isString(filter)) {
				var className = filter;
				filter = function(node) {
					return domUtils.hasClass(node, className)
				}
			}
			tagName = utils.trim(tagName).replace(/[ ]{2,}/g, " ").split(" ");
			var arr = [];
			for (var n = 0, ni; ni = tagName[n++];) {
				var list = node.getElementsByTagName(ni);
				for (var i = 0, ci; ci = list[i++];) {
					if (!filter || filter(ci)) arr.push(ci)
				}
			}
			return arr
		},
		mergeToParent: function(node) {
			var parent = node.parentNode;
			while (parent && dtd.$removeEmpty[parent.tagName]) {
				if (parent.tagName == node.tagName || parent.tagName == "A") {
					domUtils.trimWhiteTextNode(parent);
					if (parent.tagName == "SPAN" && !domUtils.isSameStyle(parent, node) || parent.tagName ==
						"A" && node.tagName == "SPAN") {
						if (parent.childNodes.length > 1 || parent !== node.parentNode) {
							node.style.cssText = parent.style.cssText + ";" + node.style.cssText;
							parent = parent.parentNode;
							continue
						} else {
							parent.style.cssText += ";" + node.style.cssText;
							if (parent.tagName == "A") {
								parent.style.textDecoration = "underline"
							}
						}
					}
					if (parent.tagName != "A") {
						parent === node.parentNode && domUtils.remove(node, true);
						break
					}
				}
				parent = parent.parentNode
			}
		},
		mergeSibling: function(node, ignorePre, ignoreNext) {
			function merge(rtl, start, node) {
				var next;
				if ((next = node[rtl]) && !domUtils.isBookmarkNode(next) && next.nodeType == 1 && domUtils
					.isSameElement(node, next)) {
					while (next.firstChild) {
						if (start == "firstChild") {
							node.insertBefore(next.lastChild, node.firstChild)
						} else {
							node.appendChild(next.firstChild)
						}
					}
					domUtils.remove(next)
				}
			}!ignorePre && merge("previousSibling", "firstChild", node);
			!ignoreNext && merge("nextSibling", "lastChild", node)
		},
		unSelectable: ie && browser.ie9below || browser.opera ? function(node) {
			node.onselectstart = function() {
				return false
			};
			node.onclick = node.onkeyup = node.onkeydown = function() {
				return false
			};
			node.unselectable = "on";
			node.setAttribute("unselectable", "on");
			for (var i = 0, ci; ci = node.all[i++];) {
				switch (ci.tagName.toLowerCase()) {
					case "iframe":
					case "textarea":
					case "input":
					case "select":
						break;
					default:
						ci.unselectable = "on";
						node.setAttribute("unselectable", "on")
				}
			}
		} : function(node) {
			node.style.MozUserSelect = node.style.webkitUserSelect = node.style.msUserSelect = node.style
				.KhtmlUserSelect = "none"
		},
		removeAttributes: function(node, attrNames) {
			attrNames = utils.isArray(attrNames) ? attrNames : utils.trim(attrNames).replace(/[ ]{2,}/g,
				" ").split(" ");
			for (var i = 0, ci; ci = attrNames[i++];) {
				ci = attrFix[ci] || ci;
				switch (ci) {
					case "className":
						node[ci] = "";
						break;
					case "style":
						node.style.cssText = "";
						var val = node.getAttributeNode("style");
						!browser.ie && val && node.removeAttributeNode(val)
				}
				node.removeAttribute(ci)
			}
		},
		createElement: function(doc, tag, attrs) {
			return domUtils.setAttributes(doc.createElement(tag), attrs)
		},
		setAttributes: function(node, attrs) {
			for (var attr in attrs) {
				if ("_propertyDelete" === attr) {
					for (var j = 0; j < attrs[attr].length; j++) {
						if (node.hasAttribute(attrs[attr][j])) {
							node.removeAttribute(attrs[attr][j])
						}
					}
					continue
				}
				if (attrs.hasOwnProperty(attr)) {
					var value = attrs[attr];
					switch (attr) {
						case "class":
							node.className = value;
							break;
						case "style":
							node.style.cssText = node.style.cssText + ";" + value;
							break;
						case "innerHTML":
							node[attr] = value;
							break;
						case "value":
							node.value = value;
							break;
						default:
							node.setAttribute(attrFix[attr] || attr, value)
					}
				}
			}
			return node
		},
		getComputedStyle: function(element, styleName) {
			var pros = "width height top left";
			if (pros.indexOf(styleName) > -1) {
				return element["offset" + styleName.replace(/^\w/, function(s) {
					return s.toUpperCase()
				})] + "px"
			}
			if (element.nodeType === 3) {
				element = element.parentNode
			}
			if (browser.ie && browser.version < 9 && styleName === "font-size" && !element.style.fontSize &&
				!dtd.$empty[element.tagName] && !dtd.$nonChild[element.tagName]) {
				var span = element.ownerDocument.createElement("span");
				span.style.cssText = "padding:0;border:0;font-family:simsun;";
				span.innerHTML = ".";
				element.appendChild(span);
				var result = span.offsetHeight;
				element.removeChild(span);
				span = null;
				return result + "px"
			}
			try {
				var value = domUtils.getStyle(element, styleName) || (window.getComputedStyle ? domUtils
					.getWindow(element).getComputedStyle(element, "").getPropertyValue(styleName) : (
						element.currentStyle || element.style)[utils.cssStyleToDomStyle(styleName)])
			} catch (e) {
				return ""
			}
			return utils.transUnitToPx(utils.fixColor(styleName, value))
		},
		removeClasses: function(elm, classNames) {
			classNames = utils.isArray(classNames) ? classNames : utils.trim(classNames).replace(/[ ]{2,}/g,
				" ").split(" ");
			for (var i = 0, ci, cls = elm.className; ci = classNames[i++];) {
				cls = cls.replace(new RegExp("\\b" + ci + "\\b"), "")
			}
			cls = utils.trim(cls).replace(/[ ]{2,}/g, " ");
			if (cls) {
				elm.className = cls
			} else {
				domUtils.removeAttributes(elm, ["class"])
			}
		},
		addClass: function(elm, classNames) {
			if (!elm) return;
			classNames = utils.trim(classNames).replace(/[ ]{2,}/g, " ").split(" ");
			for (var i = 0, ci, cls = elm.className; ci = classNames[i++];) {
				if (!new RegExp("\\b" + ci + "\\b").test(cls)) {
					cls += " " + ci
				}
			}
			elm.className = utils.trim(cls)
		},
		hasClass: function(element, className) {
			if (utils.isRegExp(className)) {
				return className.test(element.className)
			}
			className = utils.trim(className).replace(/[ ]{2,}/g, " ").split(" ");
			for (var i = 0, ci, cls = element.className; ci = className[i++];) {
				if (!new RegExp("\\b" + ci + "\\b", "i").test(cls)) {
					return false
				}
			}
			return i - 1 == className.length
		},
		preventDefault: function(evt) {
			evt.preventDefault ? evt.preventDefault() : evt.returnValue = false
		},
		removeStyle: function(element, name) {
			if (browser.ie) {
				if (name == "color") {
					name = "(^|;)" + name
				}
				element.style.cssText = element.style.cssText.replace(new RegExp(name + "[^:]*:[^;]+;?",
					"ig"), "")
			} else {
				if (element.style.removeProperty) {
					element.style.removeProperty(name)
				} else {
					element.style.removeAttribute(utils.cssStyleToDomStyle(name))
				}
			}
			if (!element.style.cssText) {
				domUtils.removeAttributes(element, ["style"])
			}
		},
		getStyle: function(element, name) {
			var value = element.style[utils.cssStyleToDomStyle(name)];
			return utils.fixColor(name, value)
		},
		setStyle: function(element, name, value) {
			element.style[utils.cssStyleToDomStyle(name)] = value;
			if (!utils.trim(element.style.cssText)) {
				this.removeAttributes(element, "style")
			}
		},
		setStyles: function(element, styles) {
			for (var name in styles) {
				if (styles.hasOwnProperty(name)) {
					domUtils.setStyle(element, name, styles[name])
				}
			}
		},
		removeDirtyAttr: function(node) {
			for (var i = 0, ci, nodes = node.getElementsByTagName("*"); ci = nodes[i++];) {
				ci.removeAttribute("_moz_dirty")
			}
			node.removeAttribute("_moz_dirty")
		},
		getChildCount: function(node, fn) {
			var count = 0,
				first = node.firstChild;
			fn = fn || function() {
				return 1
			};
			while (first) {
				if (fn(first)) {
					count++
				}
				first = first.nextSibling
			}
			return count
		},
		isEmptyNode: function(node) {
			return !node.firstChild || domUtils.getChildCount(node, function(node) {
				return !domUtils.isBr(node) && !domUtils.isBookmarkNode(node) && !domUtils
					.isWhitespace(node)
			}) == 0
		},
		clearSelectedArr: function(nodes) {
			var node;
			while (node = nodes.pop()) {
				domUtils.removeAttributes(node, ["class"])
			}
		},
		scrollToView: function(node, win, offsetTop) {
			offsetTop = offsetTop || 0;
			var getViewPaneSize = function() {
					var doc = win.document,
						mode = doc.compatMode == "CSS1Compat";
					return {
						width: (mode ? doc.documentElement.clientWidth : doc.body.clientWidth) || 0,
						height: (mode ? doc.documentElement.clientHeight : doc.body.clientHeight) || 0
					}
				},
				getScrollPosition = function(win) {
					if ("pageXOffset" in win) {
						return {
							x: win.pageXOffset || 0,
							y: win.pageYOffset || 0
						}
					} else {
						var doc = win.document;
						return {
							x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
							y: doc.documentElement.scrollTop || doc.body.scrollTop || 0
						}
					}
				};
			var winHeight = getViewPaneSize().height,
				offset = winHeight * -1 + offsetTop;
			offset += node.offsetHeight || 0;
			var elementPosition = domUtils.getXY(node);
			offset += elementPosition.y;
			var currentScroll = getScrollPosition(win).y;
			if (offset > currentScroll || offset < currentScroll - winHeight) {
				win.scrollTo({
					top: offset + (offset < 0 ? -20 : 20),
					behavior: "smooth"
				})
			}
		},
		isBr: function(node) {
			return node.nodeType == 1 && node.tagName == "BR"
		},
		isFillChar: function(node, isInStart) {
			if (node.nodeType != 3) return false;
			var text = node.nodeValue;
			if (isInStart) {
				return new RegExp("^" + domUtils.fillChar).test(text)
			}
			return !text.replace(new RegExp(domUtils.fillChar, "g"), "").length
		},
		isStartInblock: function(range) {
			var tmpRange = range.cloneRange(),
				flag = 0,
				start = tmpRange.startContainer,
				tmp;
			if (start.nodeType == 1 && start.childNodes[tmpRange.startOffset]) {
				start = start.childNodes[tmpRange.startOffset];
				var pre = start.previousSibling;
				while (pre && domUtils.isFillChar(pre)) {
					start = pre;
					pre = pre.previousSibling
				}
			}
			if (this.isFillChar(start, true) && tmpRange.startOffset == 1) {
				tmpRange.setStartBefore(start);
				start = tmpRange.startContainer
			}
			while (start && domUtils.isFillChar(start)) {
				tmp = start;
				start = start.previousSibling
			}
			if (tmp) {
				tmpRange.setStartBefore(tmp);
				start = tmpRange.startContainer
			}
			if (start.nodeType == 1 && domUtils.isEmptyNode(start) && tmpRange.startOffset == 1) {
				tmpRange.setStart(start, 0).collapse(true)
			}
			while (!tmpRange.startOffset) {
				start = tmpRange.startContainer;
				if (domUtils.isBlockElm(start) || domUtils.isBody(start)) {
					flag = 1;
					break
				}
				var pre = tmpRange.startContainer.previousSibling,
					tmpNode;
				if (!pre) {
					tmpRange.setStartBefore(tmpRange.startContainer)
				} else {
					while (pre && domUtils.isFillChar(pre)) {
						tmpNode = pre;
						pre = pre.previousSibling
					}
					if (tmpNode) {
						tmpRange.setStartBefore(tmpNode)
					} else {
						tmpRange.setStartBefore(tmpRange.startContainer)
					}
				}
			}
			return flag && !domUtils.isBody(tmpRange.startContainer) ? 1 : 0
		},
		isEmptyBlock: function(node, reg) {
			if (node.nodeType != 1) return 0;
			reg = reg || new RegExp("[  \t\r\n" + domUtils.fillChar + "]", "g");
			if (node[browser.ie ? "innerText" : "textContent"].replace(reg, "").length > 0) {
				return 0
			}
			for (var n in dtd.$isNotEmpty) {
				if (node.getElementsByTagName(n).length) {
					return 0
				}
			}
			return 1
		},
		setViewportOffset: function(element, offset) {
			var left = parseInt(element.style.left) | 0;
			var top = parseInt(element.style.top) | 0;
			var rect = element.getBoundingClientRect();
			var offsetLeft = offset.left - rect.left;
			var offsetTop = offset.top - rect.top;
			if (offsetLeft) {
				element.style.left = left + offsetLeft + "px"
			}
			if (offsetTop) {
				element.style.top = top + offsetTop + "px"
			}
		},
		fillNode: function(doc, node) {
			var tmpNode = browser.ie ? doc.createTextNode(domUtils.fillChar) : doc.createElement("br");
			node.innerHTML = "";
			node.appendChild(tmpNode)
		},
		moveChild: function(src, tag, dir) {
			while (src.firstChild) {
				if (dir && tag.firstChild) {
					tag.insertBefore(src.lastChild, tag.firstChild)
				} else {
					tag.appendChild(src.firstChild)
				}
			}
		},
		hasNoAttributes: function(node) {
			return browser.ie ? /^<\w+\s*?>/.test(node.outerHTML) : node.attributes.length == 0
		},
		isCustomeNode: function(node) {
			return node.nodeType == 1 && node.getAttribute("_ue_custom_node_")
		},
		isTagNode: function(node, tagNames) {
			return node.nodeType == 1 && new RegExp("\\b" + node.tagName + "\\b", "i").test(tagNames)
		},
		filterNodeList: function(nodelist, filter, forAll) {
			var results = [];
			if (!utils.isFunction(filter)) {
				var str = filter;
				filter = function(n) {
					return utils.indexOf(utils.isArray(str) ? str : str.split(" "), n.tagName
						.toLowerCase()) != -1
				}
			}
			utils.each(nodelist, function(n) {
				filter(n) && results.push(n)
			});
			return results.length == 0 ? null : results.length == 1 || !forAll ? results[0] : results
		},
		isInNodeEndBoundary: function(rng, node) {
			var start = rng.startContainer;
			if (start.nodeType == 3 && rng.startOffset != start.nodeValue.length) {
				return 0
			}
			if (start.nodeType == 1 && rng.startOffset != start.childNodes.length) {
				return 0
			}
			while (start !== node) {
				if (start.nextSibling) {
					return 0
				}
				start = start.parentNode
			}
			return 1
		},
		isBoundaryNode: function(node, dir) {
			var tmp;
			while (!domUtils.isBody(node)) {
				tmp = node;
				node = node.parentNode;
				if (tmp !== node[dir]) {
					return false
				}
			}
			return true
		},
		fillHtml: browser.ie11below ? "&nbsp;" : "<br/>",
		loadScript: function(url, cb) {
			var script;
			script = document.createElement("script");
			script.src = url;
			script.onload = function() {
				cb && cb({
					isNew: true
				})
			};
			document.getElementsByTagName("head")[0].appendChild(script)
		}
	};
	var fillCharReg = new RegExp(domUtils.fillChar, "g");
	(function() {
		var guid = 0,
			fillChar = domUtils.fillChar,
			fillData;

		function updateCollapse(range) {
			range.collapsed = range.startContainer && range.endContainer && range.startContainer === range
				.endContainer && range.startOffset === range.endOffset
		}

		function selectOneNode(rng) {
			return !rng.collapsed && rng.startContainer.nodeType === 1 && rng.startContainer === rng
				.endContainer && rng.endOffset - rng.startOffset === 1
		}

		function setEndPoint(toStart, node, offset, range) {
			if (node.nodeType === 1 && (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])) {
				offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1);
				node = node.parentNode
			}
			if (toStart) {
				range.startContainer = node;
				range.startOffset = offset;
				if (!range.endContainer) {
					range.collapse(true)
				}
			} else {
				range.endContainer = node;
				range.endOffset = offset;
				if (!range.startContainer) {
					range.collapse(false)
				}
			}
			updateCollapse(range);
			return range
		}

		function execContentsAction(range, action) {
			var start = range.startContainer,
				end = range.endContainer,
				startOffset = range.startOffset,
				endOffset = range.endOffset,
				doc = range.document,
				frag = doc.createDocumentFragment(),
				tmpStart, tmpEnd;
			if (start.nodeType == 1) {
				start = start.childNodes[startOffset] || (tmpStart = start.appendChild(doc.createTextNode("")))
			}
			if (end.nodeType == 1) {
				end = end.childNodes[endOffset] || (tmpEnd = end.appendChild(doc.createTextNode("")))
			}
			if (start === end && start.nodeType == 3) {
				frag.appendChild(doc.createTextNode(start.substringData(startOffset, endOffset - startOffset)));
				if (action) {
					start.deleteData(startOffset, endOffset - startOffset);
					range.collapse(true)
				}
				return frag
			}
			var current, currentLevel, clone = frag,
				startParents = domUtils.findParents(start, true),
				endParents = domUtils.findParents(end, true);
			for (var i = 0; startParents[i] == endParents[i];) {
				i++
			}
			for (var j = i, si; si = startParents[j]; j++) {
				current = si.nextSibling;
				if (si == start) {
					if (!tmpStart) {
						if (range.startContainer.nodeType == 3) {
							clone.appendChild(doc.createTextNode(start.nodeValue.slice(startOffset)));
							if (action) {
								start.deleteData(startOffset, start.nodeValue.length - startOffset)
							}
						} else {
							clone.appendChild(!action ? start.cloneNode(true) : start)
						}
					}
				} else {
					currentLevel = si.cloneNode(false);
					clone.appendChild(currentLevel)
				}
				while (current) {
					if (current === end || current === endParents[j]) {
						break
					}
					si = current.nextSibling;
					clone.appendChild(!action ? current.cloneNode(true) : current);
					current = si
				}
				clone = currentLevel
			}
			clone = frag;
			if (!startParents[i]) {
				clone.appendChild(startParents[i - 1].cloneNode(false));
				clone = clone.firstChild
			}
			for (var j = i, ei; ei = endParents[j]; j++) {
				current = ei.previousSibling;
				if (ei == end) {
					if (!tmpEnd && range.endContainer.nodeType == 3) {
						clone.appendChild(doc.createTextNode(end.substringData(0, endOffset)));
						if (action) {
							end.deleteData(0, endOffset)
						}
					}
				} else {
					currentLevel = ei.cloneNode(false);
					clone.appendChild(currentLevel)
				}
				if (j != i || !startParents[i]) {
					while (current) {
						if (current === start) {
							break
						}
						ei = current.previousSibling;
						clone.insertBefore(!action ? current.cloneNode(true) : current, clone.firstChild);
						current = ei
					}
				}
				clone = currentLevel
			}
			if (action) {
				range.setStartBefore(!endParents[i] ? endParents[i - 1] : !startParents[i] ? startParents[i -
					1] : endParents[i]).collapse(true)
			}
			tmpStart && domUtils.remove(tmpStart);
			tmpEnd && domUtils.remove(tmpEnd);
			return frag
		}
		var Range = dom.Range = function(document) {
			var me = this;
			me.startContainer = me.startOffset = me.endContainer = me.endOffset = null;
			me.document = document;
			me.collapsed = true
		};

		function removeFillData(doc, excludeNode) {
			try {
				if (fillData && domUtils.inDoc(fillData, doc)) {
					if (!fillData.nodeValue.replace(fillCharReg, "").length) {
						var tmpNode = fillData.parentNode;
						domUtils.remove(fillData);
						while (tmpNode && domUtils.isEmptyInlineElement(tmpNode) && (browser.safari ? !(domUtils
									.getPosition(tmpNode, excludeNode) & domUtils.POSITION_CONTAINS) : !tmpNode
								.contains(excludeNode))) {
							fillData = tmpNode.parentNode;
							domUtils.remove(tmpNode);
							tmpNode = fillData
						}
					} else {
						fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, "")
					}
				}
			} catch (e) {}
		}

		function mergeSibling(node, dir) {
			var tmpNode;
			node = node[dir];
			while (node && domUtils.isFillChar(node)) {
				tmpNode = node[dir];
				domUtils.remove(node);
				node = tmpNode
			}
		}
		Range.prototype = {
			cloneContents: function() {
				return this.collapsed ? null : execContentsAction(this, 0)
			},
			deleteContents: function() {
				var txt;
				if (!this.collapsed) {
					execContentsAction(this, 1)
				}
				if (browser.webkit) {
					txt = this.startContainer;
					if (txt.nodeType == 3 && !txt.nodeValue.length) {
						this.setStartBefore(txt).collapse(true);
						domUtils.remove(txt)
					}
				}
				return this
			},
			extractContents: function() {
				return this.collapsed ? null : execContentsAction(this, 2)
			},
			setStart: function(node, offset) {
				return setEndPoint(true, node, offset, this)
			},
			setEnd: function(node, offset) {
				return setEndPoint(false, node, offset, this)
			},
			setStartAfter: function(node) {
				return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1)
			},
			setStartBefore: function(node) {
				return this.setStart(node.parentNode, domUtils.getNodeIndex(node))
			},
			setEndAfter: function(node) {
				return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1)
			},
			setEndBefore: function(node) {
				return this.setEnd(node.parentNode, domUtils.getNodeIndex(node))
			},
			setStartAtFirst: function(node) {
				return this.setStart(node, 0)
			},
			setStartAtLast: function(node) {
				return this.setStart(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes
					.length)
			},
			setEndAtFirst: function(node) {
				return this.setEnd(node, 0)
			},
			setEndAtLast: function(node) {
				return this.setEnd(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes
					.length)
			},
			selectNode: function(node) {
				return this.setStartBefore(node).setEndAfter(node)
			},
			selectNodeContents: function(node) {
				return this.setStart(node, 0).setEndAtLast(node)
			},
			cloneRange: function() {
				var me = this;
				return new Range(me.document).setStart(me.startContainer, me.startOffset).setEnd(me
					.endContainer, me.endOffset)
			},
			collapse: function(toStart) {
				var me = this;
				if (toStart) {
					me.endContainer = me.startContainer;
					me.endOffset = me.startOffset
				} else {
					me.startContainer = me.endContainer;
					me.startOffset = me.endOffset
				}
				me.collapsed = true;
				return me
			},
			shrinkBoundary: function(ignoreEnd) {
				var me = this,
					child, collapsed = me.collapsed;

				function check(node) {
					return node.nodeType == 1 && !domUtils.isBookmarkNode(node) && !dtd.$empty[node
						.tagName] && !dtd.$nonChild[node.tagName]
				}
				while (me.startContainer.nodeType == 1 && (child = me.startContainer.childNodes[me
						.startOffset]) && check(child)) {
					me.setStart(child, 0)
				}
				if (collapsed) {
					return me.collapse(true)
				}
				if (!ignoreEnd) {
					while (me.endContainer.nodeType == 1 && me.endOffset > 0 && (child = me.endContainer
							.childNodes[me.endOffset - 1]) && check(child)) {
						me.setEnd(child, child.childNodes.length)
					}
				}
				return me
			},
			getCommonAncestor: function(includeSelf, ignoreTextNode) {
				var me = this,
					start = me.startContainer,
					end = me.endContainer;
				if (start === end) {
					if (includeSelf && selectOneNode(this)) {
						start = start.childNodes[me.startOffset];
						if (start.nodeType == 1) return start
					}
					return ignoreTextNode && start.nodeType == 3 ? start.parentNode : start
				}
				return domUtils.getCommonAncestor(start, end)
			},
			trimBoundary: function(ignoreEnd) {
				this.txtToElmBoundary();
				var start = this.startContainer,
					offset = this.startOffset,
					collapsed = this.collapsed,
					end = this.endContainer;
				if (start.nodeType == 3) {
					if (offset == 0) {
						this.setStartBefore(start)
					} else {
						if (offset >= start.nodeValue.length) {
							this.setStartAfter(start)
						} else {
							var textNode = domUtils.split(start, offset);
							if (start === end) {
								this.setEnd(textNode, this.endOffset - offset)
							} else if (start.parentNode === end) {
								this.endOffset += 1
							}
							this.setStartBefore(textNode)
						}
					}
					if (collapsed) {
						return this.collapse(true)
					}
				}
				if (!ignoreEnd) {
					offset = this.endOffset;
					end = this.endContainer;
					if (end.nodeType == 3) {
						if (offset == 0) {
							this.setEndBefore(end)
						} else {
							offset < end.nodeValue.length && domUtils.split(end, offset);
							this.setEndAfter(end)
						}
					}
				}
				return this
			},
			txtToElmBoundary: function(ignoreCollapsed) {
				function adjust(r, c) {
					var container = r[c + "Container"],
						offset = r[c + "Offset"];
					if (container.nodeType == 3) {
						if (!offset) {
							r["set" + c.replace(/(\w)/, function(a) {
								return a.toUpperCase()
							}) + "Before"](container)
						} else if (offset >= container.nodeValue.length) {
							r["set" + c.replace(/(\w)/, function(a) {
								return a.toUpperCase()
							}) + "After"](container)
						}
					}
				}
				if (ignoreCollapsed || !this.collapsed) {
					adjust(this, "start");
					adjust(this, "end")
				}
				return this
			},
			insertNode: function(node) {
				var first = node,
					length = 1;
				if (node.nodeType == 11) {
					first = node.firstChild;
					length = node.childNodes.length
				}
				this.trimBoundary(true);
				var start = this.startContainer,
					offset = this.startOffset;
				var nextNode = start.childNodes[offset];
				if (nextNode) {
					start.insertBefore(node, nextNode)
				} else {
					start.appendChild(node)
				}
				if (first.parentNode === this.endContainer) {
					this.endOffset = this.endOffset + length
				}
				return this.setStartBefore(first)
			},
			setCursor: function(toEnd, noFillData) {
				return this.collapse(!toEnd).select(noFillData)
			},
			createBookmark: function(serialize, same) {
				var endNode, startNode = this.document.createElement("span");
				startNode.style.cssText = "display:none;line-height:0px;";
				startNode.appendChild(this.document.createTextNode("‍"));
				startNode.id = "_baidu_bookmark_start_" + (same ? "" : guid++);
				if (!this.collapsed) {
					endNode = startNode.cloneNode(true);
					endNode.id = "_baidu_bookmark_end_" + (same ? "" : guid++)
				}
				this.insertNode(startNode);
				if (endNode) {
					this.collapse().insertNode(endNode).setEndBefore(endNode)
				}
				this.setStartAfter(startNode);
				return {
					start: serialize ? startNode.id : startNode,
					end: endNode ? serialize ? endNode.id : endNode : null,
					id: serialize
				}
			},
			moveToBookmark: function(bookmark) {
				var start = bookmark.id ? this.document.getElementById(bookmark.start) : bookmark.start,
					end = bookmark.end && bookmark.id ? this.document.getElementById(bookmark.end) :
					bookmark.end;
				this.setStartBefore(start);
				domUtils.remove(start);
				if (end) {
					this.setEndBefore(end);
					domUtils.remove(end)
				} else {
					this.collapse(true)
				}
				return this
			},
			enlarge: function(toBlock, stopFn) {
				var isBody = domUtils.isBody,
					pre, node, tmp = this.document.createTextNode("");
				if (toBlock) {
					node = this.startContainer;
					if (node.nodeType == 1) {
						if (node.childNodes[this.startOffset]) {
							pre = node = node.childNodes[this.startOffset]
						} else {
							node.appendChild(tmp);
							pre = node = tmp
						}
					} else {
						pre = node
					}
					while (1) {
						if (domUtils.isBlockElm(node)) {
							node = pre;
							while ((pre = node.previousSibling) && !domUtils.isBlockElm(pre)) {
								node = pre
							}
							this.setStartBefore(node);
							break
						}
						pre = node;
						node = node.parentNode
					}
					node = this.endContainer;
					if (node.nodeType == 1) {
						if (pre = node.childNodes[this.endOffset]) {
							node.insertBefore(tmp, pre)
						} else {
							node.appendChild(tmp)
						}
						pre = node = tmp
					} else {
						pre = node
					}
					while (1) {
						if (domUtils.isBlockElm(node)) {
							node = pre;
							while ((pre = node.nextSibling) && !domUtils.isBlockElm(pre)) {
								node = pre
							}
							this.setEndAfter(node);
							break
						}
						pre = node;
						node = node.parentNode
					}
					if (tmp.parentNode === this.endContainer) {
						this.endOffset--
					}
					domUtils.remove(tmp)
				}
				if (!this.collapsed) {
					while (this.startOffset == 0) {
						if (stopFn && stopFn(this.startContainer)) {
							break
						}
						if (isBody(this.startContainer)) {
							break
						}
						this.setStartBefore(this.startContainer)
					}
					while (this.endOffset == (this.endContainer.nodeType == 1 ? this.endContainer
							.childNodes.length : this.endContainer.nodeValue.length)) {
						if (stopFn && stopFn(this.endContainer)) {
							break
						}
						if (isBody(this.endContainer)) {
							break
						}
						this.setEndAfter(this.endContainer)
					}
				}
				return this
			},
			enlargeToBlockElm: function(ignoreEnd) {
				while (!domUtils.isBlockElm(this.startContainer)) {
					this.setStartBefore(this.startContainer)
				}
				if (!ignoreEnd) {
					while (!domUtils.isBlockElm(this.endContainer)) {
						this.setEndAfter(this.endContainer)
					}
				}
				return this
			},
			adjustmentBoundary: function() {
				if (!this.collapsed) {
					while (!domUtils.isBody(this.startContainer) && this.startOffset == this
						.startContainer[this.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"]
						.length && this.startContainer[this.startContainer.nodeType == 3 ? "nodeValue" :
							"childNodes"].length) {
						this.setStartAfter(this.startContainer)
					}
					while (!domUtils.isBody(this.endContainer) && !this.endOffset && this.endContainer[
							this.endContainer.nodeType == 3 ? "nodeValue" : "childNodes"].length) {
						this.setEndBefore(this.endContainer)
					}
				}
				return this
			},
			applyInlineStyle: function(tagName, attrs, list) {
				if (this.collapsed) return this;
				this.trimBoundary().enlarge(false, function(node) {
					return node.nodeType == 1 && domUtils.isBlockElm(node)
				}).adjustmentBoundary();
				var bookmark = this.createBookmark(),
					end = bookmark.end,
					filterFn = function(node) {
						return node.nodeType == 1 ? node.tagName.toLowerCase() != "br" : !domUtils
							.isWhitespace(node)
					},
					current = domUtils.getNextDomNode(bookmark.start, false, filterFn),
					node, pre, range = this.cloneRange();
				while (current && domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING) {
					if (current.nodeType == 3 || dtd[tagName][current.tagName]) {
						range.setStartBefore(current);
						node = current;
						while (node && (node.nodeType == 3 || dtd[tagName][node.tagName]) && node !==
							end) {
							pre = node;
							node = domUtils.getNextDomNode(node, node.nodeType == 1, null, function(
								parent) {
								return dtd[tagName][parent.tagName]
							})
						}
						var frag = range.setEndAfter(pre).extractContents(),
							elm;
						if (list && list.length > 0) {
							var level, top;
							top = level = list[0].cloneNode(false);
							for (var i = 1, ci; ci = list[i++];) {
								level.appendChild(ci.cloneNode(false));
								level = level.firstChild
							}
							elm = level
						} else {
							elm = range.document.createElement(tagName)
						}
						if (attrs) {
							domUtils.setAttributes(elm, attrs)
						}
						elm.appendChild(frag);
						if (elm.tagName == "SPAN" && attrs && attrs.style) {
							utils.each(elm.getElementsByTagName("span"), function(s) {
								s.style.cssText = s.style.cssText + ";" + attrs.style
							})
						}
						range.insertNode(list ? top : elm);
						var aNode;
						if (tagName == "span" && attrs.style && /text\-decoration/.test(attrs.style) &&
							(aNode = domUtils.findParentByTagName(elm, "a", true))) {
							domUtils.setAttributes(aNode, attrs);
							domUtils.remove(elm, true);
							elm = aNode
						} else {
							domUtils.mergeSibling(elm);
							domUtils.clearEmptySibling(elm)
						}
						domUtils.mergeChild(elm, attrs);
						current = domUtils.getNextDomNode(elm, false, filterFn);
						domUtils.mergeToParent(elm);
						if (node === end) {
							break
						}
					} else {
						current = domUtils.getNextDomNode(current, true, filterFn)
					}
				}
				return this.moveToBookmark(bookmark)
			},
			removeInlineStyle: function(tagNames) {
				if (this.collapsed) return this;
				tagNames = utils.isArray(tagNames) ? tagNames : [tagNames];
				this.shrinkBoundary().adjustmentBoundary();
				var start = this.startContainer,
					end = this.endContainer;
				while (1) {
					if (start.nodeType == 1) {
						if (utils.indexOf(tagNames, start.tagName.toLowerCase()) > -1) {
							break
						}
						if (start.tagName.toLowerCase() == "body") {
							start = null;
							break
						}
					}
					start = start.parentNode
				}
				while (1) {
					if (end.nodeType == 1) {
						if (utils.indexOf(tagNames, end.tagName.toLowerCase()) > -1) {
							break
						}
						if (end.tagName.toLowerCase() == "body") {
							end = null;
							break
						}
					}
					end = end.parentNode
				}
				var bookmark = this.createBookmark(),
					frag, tmpRange;
				if (start) {
					tmpRange = this.cloneRange().setEndBefore(bookmark.start).setStartBefore(start);
					frag = tmpRange.extractContents();
					tmpRange.insertNode(frag);
					domUtils.clearEmptySibling(start, true);
					start.parentNode.insertBefore(bookmark.start, start)
				}
				if (end) {
					tmpRange = this.cloneRange().setStartAfter(bookmark.end).setEndAfter(end);
					frag = tmpRange.extractContents();
					tmpRange.insertNode(frag);
					domUtils.clearEmptySibling(end, false, true);
					end.parentNode.insertBefore(bookmark.end, end.nextSibling)
				}
				var current = domUtils.getNextDomNode(bookmark.start, false, function(node) {
						return node.nodeType == 1
					}),
					next;
				while (current && current !== bookmark.end) {
					next = domUtils.getNextDomNode(current, true, function(node) {
						return node.nodeType == 1
					});
					if (utils.indexOf(tagNames, current.tagName.toLowerCase()) > -1) {
						domUtils.remove(current, true)
					}
					current = next
				}
				return this.moveToBookmark(bookmark)
			},
			getClosedNode: function() {
				var node;
				if (!this.collapsed) {
					var range = this.cloneRange().adjustmentBoundary().shrinkBoundary();
					if (selectOneNode(range)) {
						var child = range.startContainer.childNodes[range.startOffset];
						if (child && child.nodeType === 1 && (dtd.$empty[child.tagName] || dtd
								.$nonChild[child.tagName])) {
							node = child
						}
					}
				}
				return node
			},
			select: browser.ie ? function(noFillData, textRange) {
				var nativeRange;
				if (!this.collapsed) this.shrinkBoundary();
				var node = this.getClosedNode();
				if (node && !textRange) {
					try {
						nativeRange = this.document.body.createControlRange();
						nativeRange.addElement(node);
						nativeRange.select()
					} catch (e) {}
					return this
				}
				var bookmark = this.createBookmark(),
					start = bookmark.start,
					end;
				nativeRange = this.document.body.createTextRange();
				nativeRange.moveToElementText(start);
				nativeRange.moveStart("character", 1);
				if (!this.collapsed) {
					var nativeRangeEnd = this.document.body.createTextRange();
					end = bookmark.end;
					nativeRangeEnd.moveToElementText(end);
					nativeRange.setEndPoint("EndToEnd", nativeRangeEnd)
				} else {
					if (!noFillData && this.startContainer.nodeType != 3) {
						var tmpText = this.document.createTextNode(fillChar),
							tmp = this.document.createElement("span");
						tmp.appendChild(this.document.createTextNode(fillChar));
						start.parentNode.insertBefore(tmp, start);
						start.parentNode.insertBefore(tmpText, start);
						removeFillData(this.document, tmpText);
						fillData = tmpText;
						mergeSibling(tmp, "previousSibling");
						mergeSibling(start, "nextSibling");
						nativeRange.moveStart("character", -1);
						nativeRange.collapse(true)
					}
				}
				this.moveToBookmark(bookmark);
				tmp && domUtils.remove(tmp);
				try {
					nativeRange.select()
				} catch (e) {}
				return this
			} : function(notInsertFillData) {
				function checkOffset(rng) {
					function check(node, offset, dir) {
						if (node.nodeType == 3 && node.nodeValue.length < offset) {
							rng[dir + "Offset"] = node.nodeValue.length
						}
					}
					check(rng.startContainer, rng.startOffset, "start");
					check(rng.endContainer, rng.endOffset, "end")
				}
				var win = domUtils.getWindow(this.document),
					sel = win.getSelection(),
					txtNode;
				browser.gecko ? this.document.body.focus() : win.focus();
				if (sel) {
					sel.removeAllRanges();
					if (this.collapsed && !notInsertFillData) {
						var start = this.startContainer,
							child = start;
						if (start.nodeType == 1) {
							child = start.childNodes[this.startOffset]
						}
						if (!(start.nodeType == 3 && this.startOffset) && (child ? !child
								.previousSibling || child.previousSibling.nodeType != 3 : !start
								.lastChild || start.lastChild.nodeType != 3)) {
							txtNode = this.document.createTextNode(fillChar);
							this.insertNode(txtNode);
							removeFillData(this.document, txtNode);
							mergeSibling(txtNode, "previousSibling");
							mergeSibling(txtNode, "nextSibling");
							fillData = txtNode;
							this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true)
						}
					}
					var nativeRange = this.document.createRange();
					if (this.collapsed && browser.opera && this.startContainer.nodeType == 1) {
						var child = this.startContainer.childNodes[this.startOffset];
						if (!child) {
							child = this.startContainer.lastChild;
							if (child && domUtils.isBr(child)) {
								this.setStartBefore(child).collapse(true)
							}
						} else {
							while (child && domUtils.isBlockElm(child)) {
								if (child.nodeType == 1 && child.childNodes[0]) {
									child = child.childNodes[0]
								} else {
									break
								}
							}
							child && this.setStartBefore(child).collapse(true)
						}
					}
					checkOffset(this);
					nativeRange.setStart(this.startContainer, this.startOffset);
					nativeRange.setEnd(this.endContainer, this.endOffset);
					sel.addRange(nativeRange)
				}
				return this
			},
			scrollToView: function(win, offset) {
				win = win ? window : domUtils.getWindow(this.document);
				offset = offset || win.innerHeight - 100;
				var me = this,
					span = me.document.createElement("span");
				span.innerHTML = "&nbsp;";
				me.cloneRange().insertNode(span);
				domUtils.scrollToView(span, win, offset);
				domUtils.remove(span);
				return me
			},
			inFillChar: function() {
				var start = this.startContainer;
				if (this.collapsed && start.nodeType == 3 && start.nodeValue.replace(new RegExp("^" +
						domUtils.fillChar), "").length + 1 == start.nodeValue.length) {
					return true
				}
				return false
			},
			createAddress: function(ignoreEnd, ignoreTxt) {
				var addr = {},
					me = this;

				function getAddress(isStart) {
					var node = isStart ? me.startContainer : me.endContainer;
					var parents = domUtils.findParents(node, true, function(node) {
							return !domUtils.isBody(node)
						}),
						addrs = [];
					for (var i = 0, ci; ci = parents[i++];) {
						addrs.push(domUtils.getNodeIndex(ci, ignoreTxt))
					}
					var firstIndex = 0;
					if (ignoreTxt) {
						if (node.nodeType == 3) {
							var tmpNode = node.previousSibling;
							while (tmpNode && tmpNode.nodeType == 3) {
								firstIndex += tmpNode.nodeValue.replace(fillCharReg, "").length;
								tmpNode = tmpNode.previousSibling
							}
							firstIndex += isStart ? me.startOffset : me.endOffset
						} else {
							node = node.childNodes[isStart ? me.startOffset : me.endOffset];
							if (node) {
								firstIndex = domUtils.getNodeIndex(node, ignoreTxt)
							} else {
								node = isStart ? me.startContainer : me.endContainer;
								var first = node.firstChild;
								while (first) {
									if (domUtils.isFillChar(first)) {
										first = first.nextSibling;
										continue
									}
									firstIndex++;
									if (first.nodeType == 3) {
										while (first && first.nodeType == 3) {
											first = first.nextSibling
										}
									} else {
										first = first.nextSibling
									}
								}
							}
						}
					} else {
						firstIndex = isStart ? domUtils.isFillChar(node) ? 0 : me.startOffset : me
							.endOffset
					}
					if (firstIndex < 0) {
						firstIndex = 0
					}
					addrs.push(firstIndex);
					return addrs
				}
				addr.startAddress = getAddress(true);
				if (!ignoreEnd) {
					addr.endAddress = me.collapsed ? [].concat(addr.startAddress) : getAddress()
				}
				return addr
			},
			moveToAddress: function(addr, ignoreEnd) {
				var me = this;

				function getNode(address, isStart) {
					var tmpNode = me.document.body,
						parentNode, offset;
					for (var i = 0, ci, l = address.length; i < l; i++) {
						ci = address[i];
						parentNode = tmpNode;
						tmpNode = tmpNode.childNodes[ci];
						if (!tmpNode) {
							offset = ci;
							break
						}
					}
					if (isStart) {
						if (tmpNode) {
							me.setStartBefore(tmpNode)
						} else {
							me.setStart(parentNode, offset)
						}
					} else {
						if (tmpNode) {
							me.setEndBefore(tmpNode)
						} else {
							me.setEnd(parentNode, offset)
						}
					}
				}
				getNode(addr.startAddress, true);
				!ignoreEnd && addr.endAddress && getNode(addr.endAddress);
				return me
			},
			equals: function(rng) {
				for (var p in this) {
					if (this.hasOwnProperty(p)) {
						if (this[p] !== rng[p]) return false
					}
				}
				return true
			},
			traversal: function(doFn, filterFn) {
				if (this.collapsed) return this;
				var bookmark = this.createBookmark(),
					end = bookmark.end,
					current = domUtils.getNextDomNode(bookmark.start, false, filterFn);
				while (current && current !== end && domUtils.getPosition(current, end) & domUtils
					.POSITION_PRECEDING) {
					var tmpNode = domUtils.getNextDomNode(current, false, filterFn);
					doFn(current);
					current = tmpNode
				}
				return this.moveToBookmark(bookmark)
			}
		}
	})();
	(function() {
		function getBoundaryInformation(range, start) {
			var getIndex = domUtils.getNodeIndex;
			range = range.duplicate();
			range.collapse(start);
			var parent = range.parentElement();
			if (!parent.hasChildNodes()) {
				return {
					container: parent,
					offset: 0
				}
			}
			var siblings = parent.children,
				child, testRange = range.duplicate(),
				startIndex = 0,
				endIndex = siblings.length - 1,
				index = -1,
				distance;
			while (startIndex <= endIndex) {
				index = Math.floor((startIndex + endIndex) / 2);
				child = siblings[index];
				testRange.moveToElementText(child);
				var position = testRange.compareEndPoints("StartToStart", range);
				if (position > 0) {
					endIndex = index - 1
				} else if (position < 0) {
					startIndex = index + 1
				} else {
					return {
						container: parent,
						offset: getIndex(child)
					}
				}
			}
			if (index == -1) {
				testRange.moveToElementText(parent);
				testRange.setEndPoint("StartToStart", range);
				distance = testRange.text.replace(/(\r\n|\r)/g, "\n").length;
				siblings = parent.childNodes;
				if (!distance) {
					child = siblings[siblings.length - 1];
					return {
						container: child,
						offset: child.nodeValue.length
					}
				}
				var i = siblings.length;
				while (distance > 0) {
					distance -= siblings[--i].nodeValue.length
				}
				return {
					container: siblings[i],
					offset: -distance
				}
			}
			testRange.collapse(position > 0);
			testRange.setEndPoint(position > 0 ? "StartToStart" : "EndToStart", range);
			distance = testRange.text.replace(/(\r\n|\r)/g, "\n").length;
			if (!distance) {
				return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ? {
					container: parent,
					offset: getIndex(child) + (position > 0 ? 0 : 1)
				} : {
					container: child,
					offset: position > 0 ? 0 : child.childNodes.length
				}
			}
			while (distance > 0) {
				try {
					var pre = child;
					child = child[position > 0 ? "previousSibling" : "nextSibling"];
					distance -= child.nodeValue.length
				} catch (e) {
					return {
						container: parent,
						offset: getIndex(pre)
					}
				}
			}
			return {
				container: child,
				offset: position > 0 ? -distance : child.nodeValue.length + distance
			}
		}

		function transformIERangeToRange(ieRange, range) {
			if (ieRange.item) {
				range.selectNode(ieRange.item(0))
			} else {
				var bi = getBoundaryInformation(ieRange, true);
				range.setStart(bi.container, bi.offset);
				if (ieRange.compareEndPoints("StartToEnd", ieRange) != 0) {
					bi = getBoundaryInformation(ieRange, false);
					range.setEnd(bi.container, bi.offset)
				}
			}
			return range
		}

		function _getIERange(sel) {
			var ieRange;
			try {
				ieRange = sel.getNative().createRange()
			} catch (e) {
				return null
			}
			var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
			if ((el.ownerDocument || el) === sel.document) {
				return ieRange
			}
			return null
		}
		var Selection = dom.Selection = function(doc) {
			var me = this,
				iframe;
			me.document = doc;
			if (browser.ie9below) {
				iframe = domUtils.getWindow(doc).frameElement;
				domUtils.on(iframe, "beforedeactivate", function() {
					me._bakIERange = me.getIERange()
				});
				domUtils.on(iframe, "activate", function() {
					try {
						if (!_getIERange(me) && me._bakIERange) {
							me._bakIERange.select()
						}
					} catch (ex) {}
					me._bakIERange = null
				})
			}
			iframe = doc = null
		};
		Selection.prototype = {
			rangeInBody: function(rng, txtRange) {
				var node = browser.ie9below || txtRange ? rng.item ? rng.item() : rng.parentElement() :
					rng.startContainer;
				return node === this.document.body || domUtils.inDoc(node, this.document)
			},
			getNative: function() {
				var doc = this.document;
				try {
					return !doc ? null : browser.ie9below ? doc.selection : domUtils.getWindow(doc)
						.getSelection()
				} catch (e) {
					return null
				}
			},
			getIERange: function() {
				var ieRange = _getIERange(this);
				if (!ieRange) {
					if (this._bakIERange) {
						return this._bakIERange
					}
				}
				return ieRange
			},
			cache: function() {
				this.clear();
				this._cachedRange = this.getRange();
				this._cachedStartElement = this.getStart();
				this._cachedStartElementPath = this.getStartElementPath()
			},
			getStartElementPath: function() {
				if (this._cachedStartElementPath) {
					return this._cachedStartElementPath
				}
				var start = this.getStart();
				if (start) {
					return domUtils.findParents(start, true, null, true)
				}
				return []
			},
			clear: function() {
				this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null
			},
			isFocus: function() {
				try {
					if (browser.ie9below) {
						var nativeRange = _getIERange(this);
						return !!(nativeRange && this.rangeInBody(nativeRange))
					} else {
						return !!this.getNative().rangeCount
					}
				} catch (e) {
					return false
				}
			},
			getRange: function() {
				var me = this;

				function optimze(range) {
					var child = me.document.body.firstChild,
						collapsed = range.collapsed;
					while (child && child.firstChild) {
						range.setStart(child, 0);
						child = child.firstChild
					}
					if (!range.startContainer) {
						range.setStart(me.document.body, 0)
					}
					if (collapsed) {
						range.collapse(true)
					}
				}
				if (me._cachedRange != null) {
					return this._cachedRange
				}
				var range = new baidu.editor.dom.Range(me.document);
				if (browser.ie9below) {
					var nativeRange = me.getIERange();
					if (nativeRange) {
						try {
							transformIERangeToRange(nativeRange, range)
						} catch (e) {
							optimze(range)
						}
					} else {
						optimze(range)
					}
				} else {
					var sel = me.getNative();
					if (sel && sel.rangeCount) {
						var firstRange = sel.getRangeAt(0);
						var lastRange = sel.getRangeAt(sel.rangeCount - 1);
						range.setStart(firstRange.startContainer, firstRange.startOffset).setEnd(
							lastRange.endContainer, lastRange.endOffset);
						if (range.collapsed && domUtils.isBody(range.startContainer) && !range
							.startOffset) {
							optimze(range)
						}
					} else {
						if (this._bakRange && domUtils.inDoc(this._bakRange.startContainer, this
								.document)) {
							return this._bakRange
						}
						optimze(range)
					}
				}
				return this._bakRange = range
			},
			getStart: function() {
				if (this._cachedStartElement) {
					return this._cachedStartElement
				}
				var range = browser.ie9below ? this.getIERange() : this.getRange(),
					tmpRange, start, tmp, parent;
				if (browser.ie9below) {
					if (!range) {
						return this.document.body.firstChild
					}
					if (range.item) {
						return range.item(0)
					}
					tmpRange = range.duplicate();
					tmpRange.text.length > 0 && tmpRange.moveStart("character", 1);
					tmpRange.collapse(1);
					start = tmpRange.parentElement();
					parent = tmp = range.parentElement();
					while (tmp = tmp.parentNode) {
						if (tmp == start) {
							start = parent;
							break
						}
					}
				} else {
					range.shrinkBoundary();
					start = range.startContainer;
					if (start.nodeType == 1 && start.hasChildNodes()) {
						start = start.childNodes[Math.min(start.childNodes.length - 1, range
							.startOffset)]
					}
					if (start.nodeType == 3) {
						return start.parentNode
					}
				}
				return start
			},
			getText: function() {
				var nativeSel, nativeRange;
				if (this.isFocus() && (nativeSel = this.getNative())) {
					nativeRange = browser.ie9below ? nativeSel.createRange() : nativeSel.getRangeAt(0);
					return browser.ie9below ? nativeRange.text : nativeRange.toString()
				}
				return ""
			},
			clearRange: function() {
				this.getNative()[browser.ie9below ? "empty" : "removeAllRanges"]()
			}
		}
	})();
	(function() {
		var uid = 0,
			_selectionChangeTimer;

		function setValue(form, editor) {
			if (!editor.options.textarea) {
				return
			}
			var textarea;
			textarea = editor.textarea;
			if (!textarea) {
				textarea = domUtils.getElementsByTagName(form, "textarea", function(node) {
					return node.id === "ueditor_textarea_" + editor.options.textarea
				})[0]
			}
			if (!textarea) {
				textarea = domUtils.getElementsByTagName(form, "textarea", function(node) {
					return node.name === editor.options.textarea
				})[0]
			}
			if (!textarea) {
				form.appendChild(textarea = domUtils.createElement(document, "textarea", {
					name: editor.options.textarea,
					id: "ueditor_textarea_" + editor.options.textarea,
					style: "display:none"
				}))
			}
			if (textarea && !editor.textarea) {
				editor.textarea = textarea
			}!textarea.getAttribute("name") && textarea.setAttribute("name", editor.options.textarea);
			textarea.value = editor.hasContents() ? editor.options.allHtmlEnabled ? editor.getAllHtml() : editor
				.getContent(null, null, true) : ""
		}

		function loadPlugins(me) {
			for (var pi in UE.plugins) {
				UE.plugins[pi].call(me)
			}
		}

		function checkCurLang(I18N) {
			for (var lang in I18N) {
				return lang
			}
		}

		function langReadied(me) {
			me.langIsReady = true;
			me.fireEvent("langReady")
		}
		var Editor = UE.Editor = function(options) {
			var me = this;
			me.uid = uid++;
			EventBase.call(me);
			me.commands = {};
			me.options = utils.extend(utils.clone(options || {}), UEDITOR_CONFIG, true);
			me.shortcutkeys = {};
			me.inputRules = [];
			me.outputRules = [];
			me.setOpt(Editor.defaultOptions(me));
			me.loadServerConfig();
			if (!utils.isEmptyObject(UE.I18N)) {
				me.options.lang = checkCurLang(UE.I18N);
				UE.plugin.load(me);
				langReadied(me)
			} else {
				utils.loadFile(document, {
					src: me.options.langPath + me.options.lang + "/" + me.options.lang +
						".js?7a537435",
					tag: "script",
					type: "text/javascript",
					defer: "defer"
				}, function() {
					UE.plugin.load(me);
					langReadied(me)
				})
			}
			UE.instants["ueditorInstant" + me.uid] = me
		};
		Editor.prototype = {
			registerCommand: function(name, obj) {
				this.commands[name] = obj
			},
			ready: function(fn) {
				var me = this;
				if (fn) {
					me.isReady ? fn.apply(me) : me.addListener("ready", fn)
				}
			},
			setOpt: function(key, val) {
				var obj = {};
				if (utils.isString(key)) {
					obj[key] = val
				} else {
					obj = key
				}
				utils.extend(this.options, obj, true)
			},
			getOpt: function(key) {
				return this.options[key]
			},
			destroy: function() {
				var me = this;
				me.fireEvent("destroy");
				var container = me.container.parentNode;
				var textarea = me.textarea;
				if (!textarea) {
					textarea = document.createElement("textarea");
					container.parentNode.insertBefore(textarea, container)
				} else {
					textarea.style.display = ""
				}
				textarea.style.width = me.iframe.offsetWidth + "px";
				textarea.style.height = me.iframe.offsetHeight + "px";
				textarea.value = me.getContent();
				textarea.id = me.key;
				container.innerHTML = "";
				domUtils.remove(container);
				var key = me.key;
				for (var p in me) {
					if (me.hasOwnProperty(p)) {
						delete this[p]
					}
				}
				UE.delEditor(key)
			},
			render: function(container) {
				var me = this,
					options = me.options,
					getStyleValue = function(attr) {
						return parseInt(domUtils.getComputedStyle(container, attr))
					};
				if (utils.isString(container)) {
					container = document.getElementById(container)
				}
				if (container) {
					if (options.initialFrameWidth) {
						options.minFrameWidth = options.initialFrameWidth
					} else {
						options.minFrameWidth = options.initialFrameWidth = container.offsetWidth
					}
					if (options.initialFrameHeight) {
						options.minFrameHeight = options.initialFrameHeight
					} else {
						options.initialFrameHeight = options.minFrameHeight = container.offsetHeight
					}
					container.style.width = /%$/.test(options.initialFrameWidth) ? "100%" : options
						.initialFrameWidth - getStyleValue("padding-left") - getStyleValue(
							"padding-right") + "px";
					container.style.height = /%$/.test(options.initialFrameHeight) ? "100%" : options
						.initialFrameHeight - getStyleValue("padding-top") - getStyleValue(
							"padding-bottom") + "px";
					container.style.zIndex = options.zIndex;
					var additionCssHtml = [];
					for (var i in options.iframeCssUrlsAddition) {
						additionCssHtml.push("<link rel='stylesheet' type='text/css' href='" + utils
							.unhtml(options.iframeCssUrlsAddition[i]) + "'/>")
					}
					var html = (ie && browser.version < 9 ? "" : "<!DOCTYPE html>") +
						"<html xmlns='http://www.w3.org/1999/xhtml' class='view' >" + "<head>" +
						"<style type='text/css'>" +
						".view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n" +
						"body{margin:8px;font-family:sans-serif;font-size:16px;}" +
						"p{margin:5px 0;}</style>" + (options.iframeCssUrl ?
							"<link rel='stylesheet' type='text/css' href='" + utils.unhtml(options
								.iframeCssUrl) + "'/>" : "") + (options.initialStyle ? "<style>" +
							options.initialStyle + "</style>" : "") + additionCssHtml.join("") +
						"</head>" + "<body class='view' ></body>" + "<script type='text/javascript' " +
						(ie ? "defer='defer'" : "") + " id='_initialScript'>" +
						"setTimeout(function(){editor = window.parent.UE.instants['ueditorInstant" + me
						.uid + "'];editor._setup(document);},0);" +
						"var _tmpScript = document.getElementById('_initialScript');_tmpScript.parentNode.removeChild(_tmpScript);" +
						"<\/script>" + (options.iframeJsUrl ? "<script type='text/javascript' src='" +
							utils.unhtml(options.iframeJsUrl) + "'><\/script>" : "") + "</html>";
					container.appendChild(domUtils.createElement(document, "iframe", {
						id: "ueditor_" + me.uid,
						width: "100%",
						height: "100%",
						frameborder: "0",
						src: "javascript:void(function(){document.open();" + (options
								.customDomain && document.domain != location.hostname ?
								'document.domain="' + document.domain + '";' : "") +
							'document.write("' + html + '");document.close();}())'
					}));
					container.style.overflow = "hidden";
					setTimeout(function() {
						if (/%$/.test(options.initialFrameWidth)) {
							options.minFrameWidth = options.initialFrameWidth = container
								.offsetWidth
						}
						if (/%$/.test(options.initialFrameHeight)) {
							options.minFrameHeight = options.initialFrameHeight = container
								.offsetHeight;
							container.style.height = options.initialFrameHeight + "px"
						}
					})
				}
			},
			_setup: function(doc) {
				var me = this,
					options = me.options;
				if (ie) {
					doc.body.disabled = true;
					doc.body.contentEditable = true;
					doc.body.disabled = false
				} else {
					doc.body.contentEditable = true
				}
				doc.body.spellcheck = false;
				me.document = doc;
				me.window = doc.defaultView || doc.parentWindow;
				me.iframe = me.window.frameElement;
				me.body = doc.body;
				me.selection = new dom.Selection(doc);
				var geckoSel;
				if (browser.gecko && (geckoSel = this.selection.getNative())) {
					geckoSel.removeAllRanges()
				}
				this._initEvents();
				for (var form = this.iframe.parentNode; !domUtils.isBody(form); form = form
					.parentNode) {
					if (form.tagName === "FORM") {
						me.form = form;
						if (me.options.autoSyncData) {
							domUtils.on(me.window, "blur", function() {
								setValue(form, me)
							});
							domUtils.on(form, "submit", function() {
								me.fireEvent("beforesubmit")
							})
						} else {
							domUtils.on(form, "submit", function() {
								setValue(this, me);
								me.fireEvent("beforesubmit")
							})
						}
						break
					}
				}
				if (options.initialContent) {
					if (options.autoClearinitialContent) {
						var oldExecCommand = me.execCommand;
						me.execCommand = function() {
							me.fireEvent("firstBeforeExecCommand");
							return oldExecCommand.apply(me, arguments)
						};
						this._setDefaultContent(options.initialContent)
					} else this.setContent(options.initialContent, false, true)
				}
				if (domUtils.isEmptyNode(me.body)) {
					me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>"
				}
				if (options.focus) {
					setTimeout(function() {
						me.focus(me.options.focusInEnd);
						!me.options.autoClearinitialContent && me._selectionChange()
					}, 0)
				}
				if (!me.container) {
					me.container = this.iframe.parentNode
				}
				if (options.fullscreen && me.ui) {
					me.ui.setFullScreen(true)
				}
				try {
					me.document.execCommand("2D-position", false, false)
				} catch (e) {}
				try {
					me.document.execCommand("enableInlineTableEditing", false, false)
				} catch (e) {}
				try {
					me.document.execCommand("enableObjectResizing", false, false)
				} catch (e) {}
				me._bindshortcutKeys();
				me.isReady = 1;
				me.fireEvent("ready");
				options.onready && options.onready.call(me);
				if (!browser.ie9below) {
					domUtils.on(me.window, ["blur", "focus"], function(e) {
						if (e.type == "blur") {
							me._bakRange = me.selection.getRange();
							try {
								me._bakNativeRange = me.selection.getNative().getRangeAt(0);
								me.selection.getNative().removeAllRanges()
							} catch (e) {
								me._bakNativeRange = null
							}
						} else {
							try {
								me._bakRange && me._bakRange.select()
							} catch (e) {}
						}
					})
				}
				if (browser.gecko && browser.version <= 10902) {
					me.body.contentEditable = false;
					setTimeout(function() {
						me.body.contentEditable = true
					}, 100);
					setInterval(function() {
						me.body.style.height = me.iframe.offsetHeight - 20 + "px"
					}, 100)
				}!options.isShow && me.setHide();
				options.readonly && me.setDisabled()
			},
			sync: function(formId) {
				var me = this,
					form = formId ? document.getElementById(formId) : domUtils.findParent(me.iframe
						.parentNode,
						function(node) {
							return node.tagName === "FORM"
						}, true);
				form && setValue(form, me)
			},
			syncCommandState: function() {
				this.fireEvent("selectionchange")
			},
			setWidth: function(width) {
				if (width !== parseInt(this.iframe.parentNode.parentNode.style.width)) {
					this.iframe.parentNode.parentNode.style.width = width + "px"
				}
			},
			setHeight: function(height, notSetHeight) {
				if (height !== parseInt(this.iframe.parentNode.style.height)) {
					this.iframe.parentNode.style.height = height + "px"
				}!notSetHeight && (this.options.minFrameHeight = this.options.initialFrameHeight =
					height);
				this.body.style.height = height + "px";
				!notSetHeight && this.trigger("setHeight")
			},
			addshortcutkey: function(cmd, keys) {
				var obj = {};
				if (keys) {
					obj[cmd] = keys
				} else {
					obj = cmd
				}
				utils.extend(this.shortcutkeys, obj)
			},
			_bindshortcutKeys: function() {
				var me = this,
					shortcutkeys = this.shortcutkeys;
				me.addListener("keydown", function(type, e) {
					var keyCode = e.keyCode || e.which;
					for (var i in shortcutkeys) {
						var tmp = shortcutkeys[i].split(",");
						for (var t = 0, ti; ti = tmp[t++];) {
							ti = ti.split(":");
							var key = ti[0],
								param = ti[1];
							if (/^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) || /^(\d+)$/
								.test(key)) {
								if ((RegExp.$1 == "ctrl" ? e.ctrlKey || e.metaKey : 0) && (
										RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1) &&
									keyCode == RegExp.$3 || keyCode == RegExp.$1) {
									if (me.queryCommandState(i, param) != -1) me.execCommand(i,
										param);
									domUtils.preventDefault(e)
								}
							}
						}
					}
				})
			},
			getContent: function(cmd, fn, notSetCursor, ignoreBlank, formatter) {
				var me = this;
				if (cmd && utils.isFunction(cmd)) {
					fn = cmd;
					cmd = ""
				}
				if (fn ? !fn() : !this.hasContents()) {
					return ""
				}
				me.fireEvent("beforegetcontent");
				var root = UE.htmlparser(me.body.innerHTML, ignoreBlank);
				me.filterOutputRule(root);
				me.fireEvent("aftergetcontent", cmd, root);
				return root.toHtml(formatter)
			},
			getAllHtml: function() {
				var me = this,
					headHtml = [],
					html = "";
				me.fireEvent("getAllHtml", headHtml);
				if (browser.ie && browser.version > 8) {
					var headHtmlForIE9 = "";
					utils.each(me.document.styleSheets, function(si) {
						headHtmlForIE9 += si.href ?
							'<link rel="stylesheet" type="text/css" href="' + si.href + '" />' :
							"<style>" + si.cssText + "</style>"
					});
					utils.each(me.document.getElementsByTagName("script"), function(si) {
						headHtmlForIE9 += si.outerHTML
					})
				}
				return "<html><head>" + (me.options.charset ?
					'<meta http-equiv="Content-Type" content="text/html; charset=' + me.options
					.charset + '"/>' : "") + (headHtmlForIE9 || me.document.getElementsByTagName(
					"head")[0].innerHTML) + headHtml.join("\n") + "</head>" + "<body " + (ie &&
					browser.version < 9 ? 'class="view"' : "") + ">" + me.getContent(null, null,
					true) + "</body></html>"
			},
			getPlainTxt: function() {
				var reg = new RegExp(domUtils.fillChar, "g"),
					html = this.body.innerHTML.replace(/[\n\r]/g, "");
				html = html.replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, "\n").replace(/<br\/?>/gi,
					"\n").replace(/<[^>/]+>/g, "").replace(/(\n)?<\/([^>]+)>/g, function(a, b, c) {
					return dtd.$block[c] ? "\n" : b ? b : ""
				});
				return html.replace(reg, "").replace(/\u00a0/g, " ").replace(/&nbsp;/g, " ")
			},
			getContentTxt: function() {
				var reg = new RegExp(domUtils.fillChar, "g");
				return this.body[browser.ie ? "innerText" : "textContent"].replace(reg, "").replace(
					/\u00a0/g, " ")
			},
			setContent: function(html, isAppendTo, notFireSelectionchange) {
				var me = this;
				me.fireEvent("beforesetcontent", html);
				var root = UE.htmlparser(html);
				me.filterInputRule(root);
				html = root.toHtml();
				me.body.innerHTML = (isAppendTo ? me.body.innerHTML : "") + html;

				function isCdataDiv(node) {
					return node.tagName == "DIV" && node.getAttribute("cdata_tag")
				}
				if (me.options.enterTag == "p") {
					var child = this.body.firstChild,
						tmpNode;
					if (!child || child.nodeType == 1 && (dtd.$cdata[child.tagName] || isCdataDiv(
							child) || domUtils.isCustomeNode(child)) && child === this.body.lastChild) {
						this.body.innerHTML = "<p>" + (browser.ie ? "&nbsp;" : "<br/>") + "</p>" + this
							.body.innerHTML
					} else {
						var p = me.document.createElement("p");
						while (child) {
							while (child && (child.nodeType == 3 || child.nodeType == 1 && dtd.p[child
									.tagName] && !dtd.$cdata[child.tagName])) {
								tmpNode = child.nextSibling;
								p.appendChild(child);
								child = tmpNode
							}
							if (p.firstChild) {
								if (!child) {
									me.body.appendChild(p);
									break
								} else {
									child.parentNode.insertBefore(p, child);
									p = me.document.createElement("p")
								}
							}
							child = child.nextSibling
						}
					}
				}
				me.fireEvent("aftersetcontent");
				me.fireEvent("contentchange");
				!notFireSelectionchange && me._selectionChange();
				me._bakRange = me._bakIERange = me._bakNativeRange = null;
				var geckoSel;
				if (browser.gecko && (geckoSel = this.selection.getNative())) {
					geckoSel.removeAllRanges()
				}
				if (me.options.autoSyncData) {
					me.form && setValue(me.form, me)
				}
			},
			focus: function(toEnd) {
				try {
					var me = this,
						rng = me.selection.getRange();
					if (toEnd) {
						var node = me.body.lastChild;
						if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
							if (domUtils.isEmptyBlock(node)) {
								rng.setStartAtFirst(node)
							} else {
								rng.setStartAtLast(node)
							}
							rng.collapse(true)
						}
						rng.setCursor(true)
					} else {
						if (!rng.collapsed && domUtils.isBody(rng.startContainer) && rng.startOffset ==
							0) {
							var node = me.body.firstChild;
							if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
								rng.setStartAtFirst(node).collapse(true)
							}
						}
						rng.select(true)
					}
					this.fireEvent("focus selectionchange")
				} catch (e) {}
			},
			isFocus: function() {
				return this.selection.isFocus()
			},
			blur: function() {
				var sel = this.selection.getNative();
				if (sel.empty && browser.ie) {
					var nativeRng = document.body.createTextRange();
					nativeRng.moveToElementText(document.body);
					nativeRng.collapse(true);
					nativeRng.select();
					sel.empty()
				} else {
					sel.removeAllRanges()
				}
			},
			_initEvents: function() {
				var me = this,
					doc = me.document,
					win = me.window;
				me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
				domUtils.on(doc, ["click", "contextmenu", "mousedown", "keydown", "keyup", "keypress",
					"mouseup", "mouseover", "mouseout", "selectstart"
				], me._proxyDomEvent);
				domUtils.on(win, ["focus", "blur"], me._proxyDomEvent);
				domUtils.on(me.body, "drop", function(e) {
					if (browser.gecko && e.stopPropagation) {
						e.stopPropagation()
					}
					me.fireEvent("contentchange")
				});
				domUtils.on(me.body, "dblclick", function(e) {
					try {
						var node = me.body.lastChild;
						if (!node) {
							return
						}
						var rect = node.getBoundingClientRect();
						if (e.clientY > rect.top + rect.height) {
							var p = document.createElement("p");
							p.innerHTML = "<br />";
							me.body.appendChild(p);
							setTimeout(function() {
								me.focus(true)
							}, 100)
						}
					} catch (e) {
						console.error("auto insert p at end", e)
					}
				});
				domUtils.on(doc, ["mouseup", "keydown"], function(evt) {
					if (evt.type === "keydown" && (evt.ctrlKey || evt.metaKey || evt.shiftKey ||
							evt.altKey)) {
						return
					}
					if (evt.button === 2) return;
					me._selectionChange(250, evt)
				})
			},
			_proxyDomEvent: function(evt) {
				if (this.fireEvent("before" + evt.type.replace(/^on/, "").toLowerCase()) === false) {
					return false
				}
				if (this.fireEvent(evt.type.replace(/^on/, ""), evt) === false) {
					return false
				}
				return this.fireEvent("after" + evt.type.replace(/^on/, "").toLowerCase())
			},
			_selectionChange: function(delay, evt) {
				var me = this;
				var hackForMouseUp = false;
				var mouseX, mouseY;
				if (browser.ie && browser.version < 9 && evt && evt.type == "mouseup") {
					var range = this.selection.getRange();
					if (!range.collapsed) {
						hackForMouseUp = true;
						mouseX = evt.clientX;
						mouseY = evt.clientY
					}
				}
				clearTimeout(_selectionChangeTimer);
				_selectionChangeTimer = setTimeout(function() {
					if (!me.selection || !me.selection.getNative()) {
						return
					}
					var ieRange;
					if (hackForMouseUp && me.selection.getNative().type == "None") {
						ieRange = me.document.body.createTextRange();
						try {
							ieRange.moveToPoint(mouseX, mouseY)
						} catch (ex) {
							ieRange = null
						}
					}
					var bakGetIERange;
					if (ieRange) {
						bakGetIERange = me.selection.getIERange;
						me.selection.getIERange = function() {
							return ieRange
						}
					}
					me.selection.cache();
					if (bakGetIERange) {
						me.selection.getIERange = bakGetIERange
					}
					if (me.selection._cachedRange && me.selection._cachedStartElement) {
						me.fireEvent("beforeselectionchange");
						me.fireEvent("selectionchange", !!evt);
						me.fireEvent("afterselectionchange");
						me.selection.clear()
					}
				}, delay || 50)
			},
			_callCmdFn: function(fnName, args) {
				var cmdName = args[0].toLowerCase(),
					cmd, cmdFn;
				cmd = this.commands[cmdName] || UE.commands[cmdName];
				cmdFn = cmd && cmd[fnName];
				if ((!cmd || !cmdFn) && fnName == "queryCommandState") {
					return 0
				} else if (cmdFn) {
					return cmdFn.apply(this, args)
				}
			},
			execCommand: function(cmdName) {
				cmdName = cmdName.toLowerCase();
				var me = this,
					result, cmd = me.commands[cmdName] || UE.commands[cmdName];
				if (!cmd || !cmd.execCommand) {
					return null
				}
				if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
					me.__hasEnterExecCommand = true;
					if (me.queryCommandState.apply(me, arguments) != -1) {
						me.fireEvent("saveScene");
						me.fireEvent.apply(me, ["beforeexeccommand", cmdName].concat(arguments));
						result = this._callCmdFn("execCommand", arguments);
						me.fireEvent.apply(me, ["afterexeccommand", cmdName].concat(arguments));
						me.fireEvent("saveScene")
					}
					me.__hasEnterExecCommand = false
				} else {
					result = this._callCmdFn("execCommand", arguments);
					!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange &&
						me.fireEvent("contentchange")
				}!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange && me
					._selectionChange();
				return result
			},
			queryCommandState: function(cmdName) {
				return this._callCmdFn("queryCommandState", arguments)
			},
			queryCommandValue: function(cmdName) {
				return this._callCmdFn("queryCommandValue", arguments)
			},
			hasContents: function(tags) {
				if (tags) {
					for (var i = 0, ci; ci = tags[i++];) {
						if (this.document.getElementsByTagName(ci).length > 0) {
							return true
						}
					}
				}
				if (!domUtils.isEmptyBlock(this.body)) {
					return true
				}
				tags = ["div"];
				for (i = 0; ci = tags[i++];) {
					var nodes = domUtils.getElementsByTagName(this.document, ci);
					for (var n = 0, cn; cn = nodes[n++];) {
						if (domUtils.isCustomeNode(cn)) {
							return true
						}
					}
				}
				tags = ["video", "iframe"];
				for (i = 0; ci = tags[i++];) {
					var nodes = domUtils.getElementsByTagName(this.document, ci);
					for (var n = 0, cn; cn = nodes[n++];) {
						return true
					}
				}
				return false
			},
			reset: function() {
				this.clear();
				this.fireEvent("reset")
			},
			clear: function() {
				this.setContent("")
			},
			setEnabled: function() {
				var me = this,
					range;
				if (me.body.contentEditable === "false") {
					me.body.contentEditable = true;
					range = me.selection.getRange();
					try {
						range.moveToBookmark(me.lastBk);
						delete me.lastBk
					} catch (e) {
						range.setStartAtFirst(me.body).collapse(true)
					}
					range.select(true);
					if (me.bkqueryCommandState) {
						me.queryCommandState = me.bkqueryCommandState;
						delete me.bkqueryCommandState
					}
					if (me.bkqueryCommandValue) {
						me.queryCommandValue = me.bkqueryCommandValue;
						delete me.bkqueryCommandValue
					}
					me.fireEvent("selectionchange")
				}
			},
			enable: function() {
				return this.setEnabled()
			},
			setDisabled: function(except) {
				var me = this;
				except = except ? utils.isArray(except) ? except : [except] : [];
				if (me.body.contentEditable == "true") {
					if (!me.lastBk) {
						me.lastBk = me.selection.getRange().createBookmark(true)
					}
					me.body.contentEditable = false;
					me.bkqueryCommandState = me.queryCommandState;
					me.bkqueryCommandValue = me.queryCommandValue;
					me.queryCommandState = function(type) {
						if (utils.indexOf(except, type) != -1) {
							return me.bkqueryCommandState.apply(me, arguments)
						}
						return -1
					};
					me.queryCommandValue = function(type) {
						if (utils.indexOf(except, type) != -1) {
							return me.bkqueryCommandValue.apply(me, arguments)
						}
						return null
					};
					me.fireEvent("selectionchange")
				}
			},
			disable: function(except) {
				return this.setDisabled(except)
			},
			_setDefaultContent: function() {
				function clear() {
					var me = this;
					if (me.document.getElementById("initContent")) {
						me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
						me.removeListener("firstBeforeExecCommand focus", clear);
						setTimeout(function() {
							me.focus();
							me._selectionChange()
						}, 0)
					}
				}
				return function(cont) {
					var me = this;
					me.body.innerHTML = '<p id="initContent">' + cont + "</p>";
					me.addListener("firstBeforeExecCommand focus", clear)
				}
			}(),
			setShow: function() {
				var me = this,
					range = me.selection.getRange();
				if (me.container.style.display == "none") {
					try {
						range.moveToBookmark(me.lastBk);
						delete me.lastBk
					} catch (e) {
						range.setStartAtFirst(me.body).collapse(true)
					}
					setTimeout(function() {
						range.select(true)
					}, 100);
					me.container.style.display = ""
				}
			},
			show: function() {
				return this.setShow()
			},
			setHide: function() {
				var me = this;
				if (!me.lastBk) {
					me.lastBk = me.selection.getRange().createBookmark(true)
				}
				me.container.style.display = "none"
			},
			hide: function() {
				return this.setHide()
			},
			getLang: function(path) {
				var lang = UE.I18N[this.options.lang];
				if (!lang) {
					throw Error("not import language file")
				}
				path = (path || "").split(".");
				for (var i = 0, ci; ci = path[i++];) {
					lang = lang[ci];
					if (!lang) break
				}
				return lang
			},
			getContentLength: function(ingoneHtml, tagNames) {
				var count = this.getContent(false, false, true).length;
				if (ingoneHtml) {
					tagNames = (tagNames || []).concat(["hr", "img", "iframe"]);
					count = this.getContentTxt().replace(/[\t\r\n]+/g, "").length;
					for (var i = 0, ci; ci = tagNames[i++];) {
						count += this.document.getElementsByTagName(ci).length
					}
				}
				return count
			},
			getScrollTop: function() {
				return Math.max(this.document.documentElement.scrollTop, this.document.body.scrollTop)
			},
			getScrollLeft: function() {
				return Math.max(this.document.documentElement.scrollLeft, this.document.body.scrollLeft)
			},
			addInputRule: function(rule) {
				this.inputRules.push(rule)
			},
			filterInputRule: function(root) {
				for (var i = 0, ci; ci = this.inputRules[i++];) {
					ci.call(this, root)
				}
			},
			addOutputRule: function(rule) {
				this.outputRules.push(rule)
			},
			filterOutputRule: function(root) {
				for (var i = 0, ci; ci = this.outputRules[i++];) {
					ci.call(this, root)
				}
			},
			getActionUrl: function(action) {				
				var serverUrl = this.getOpt("serverUrl");
				if (!action) {
					return serverUrl
				}
				var actionName = this.getOpt(action) || action,
					imageUrl = this.getOpt("imageUrl");
				if (!serverUrl && imageUrl) {
					serverUrl = imageUrl.replace(/^(.*[\/]).+([\.].+)$/, "$1controller$2")
				}
				if (serverUrl) {
					serverUrl = serverUrl + (serverUrl.indexOf("?") === -1 ? "?" : "&") + "action=" + (
						actionName || "");
					return utils.formatUrl(serverUrl)
				} else {
					return ""
				}
			}
		};
		utils.inherits(Editor, EventBase)
	})();
	UE.Editor.defaultOptions = function(editor) {
		var _url = editor.options.UEDITOR_HOME_URL;
		return {
			isShow: true,
			initialContent: "",
			initialStyle: "",
			autoClearinitialContent: false,
			iframeCssUrl: _url + "themes/iframe.css?c20ec247",
			iframeCssUrlsAddition: [],
			textarea: "",
			focus: false,
			focusInEnd: true,
			autoClearEmptyNode: true,
			fullscreen: false,
			readonly: false,
			zIndex: 999,
			imagePopup: true,
			enterTag: "p",
			customDomain: false,
			lang: "zh-cn",
			langPath: _url + "lang/",
			theme: "default",
			themePath: _url + "themes/",
			allHtmlEnabled: false,
			scaleEnabled: false,
			tableNativeEditInFF: false,
			autoSyncData: true,
			fileNameFormat: "{time}{rand:6}"
		}
	};
	(function() {
		UE.Editor.prototype.loadServerConfig = function() {
			var me = this;
			setTimeout(function() {
				try {					
					me.options.imageUrl && me.setOpt("serverUrl", me.options.imageUrl.replace(
						/^(.*[\/]).+([\.].+)$/, "$1controller$2"));
					var configUrl = me.getActionUrl("config"),
						isJsonp = false
					me._serverConfigLoaded = false;
					configUrl && UE.ajax.request(configUrl, {
						method: "GET",
						dataType: isJsonp ? "jsonp" : "",
						headers: me.options.serverHeaders || {},
						onsuccess: function(r) {
							try {
								var config = isJsonp ? r : eval("(" + r.responseText +
									")");
								config = me.options.serverResponsePrepare(config);
								me.options = utils.merge(me.options, config);
								me.fireEvent("serverConfigLoaded");
								me._serverConfigLoaded = true
							} catch (e) {
								showErrorMsg(me.getLang("loadconfigFormatError"))
							}
						},
						onerror: function() {
							showErrorMsg(me.getLang("loadconfigHttpError"))
						}
					})
				} catch (e) {	
					showErrorMsg(me.getLang("loadconfigError"))
				}
			});

			function showErrorMsg(msg) {
				console && console.error(msg)
			}
		};
		UE.Editor.prototype.isServerConfigLoaded = function() {
			var me = this;
			return me._serverConfigLoaded || false
		};
		UE.Editor.prototype.afterConfigReady = function(handler) {
			if (!handler || !utils.isFunction(handler)) return;
			var me = this;
			var readyHandler = function() {
				handler.apply(me, arguments);
				me.removeListener("serverConfigLoaded", readyHandler)
			};
			if (me.isServerConfigLoaded()) {
				handler.call(me, "serverConfigLoaded")
			} else {
				me.addListener("serverConfigLoaded", readyHandler)
			}
		}
	})();
	UE.ajax = function() {
		var fnStr = "XMLHttpRequest()";
		try {
			new ActiveXObject("Msxml2.XMLHTTP");
			fnStr = "ActiveXObject('Msxml2.XMLHTTP')"
		} catch (e) {
			try {
				new ActiveXObject("Microsoft.XMLHTTP");
				fnStr = "ActiveXObject('Microsoft.XMLHTTP')"
			} catch (e) {}
		}
		var creatAjaxRequest = new Function("return new " + fnStr);

		function json2str(json) {
			var strArr = [];
			for (var i in json) {
				if (i == "method" || i == "timeout" || i == "async" || i == "dataType" || i == "callback")
					continue;
				if (json[i] == undefined || json[i] == null) continue;
				if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() ==
						"object")) {
					strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]))
				} else if (utils.isArray(json[i])) {
					for (var j = 0; j < json[i].length; j++) {
						strArr.push(encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j]))
					}
				}
			}
			return strArr.join("&")
		}

		function doAjax(url, ajaxOptions) {
			var xhr = creatAjaxRequest(),
				timeIsOut = false,
				defaultAjaxOptions = {
					method: "POST",
					timeout: 5e3,
					async: true,
					headers: {},
					data: {},
					onsuccess: function() {},
					onerror: function() {}
				};
			if (typeof url === "object") {
				ajaxOptions = url;
				url = ajaxOptions.url
			}
			if (!xhr || !url) return;
			var ajaxOpts = ajaxOptions ? utils.extend(defaultAjaxOptions, ajaxOptions) : defaultAjaxOptions;
			var submitStr = json2str(ajaxOpts);
			if (!utils.isEmptyObject(ajaxOpts.data)) {
				submitStr += (submitStr ? "&" : "") + json2str(ajaxOpts.data)
			}
			var timerID = setTimeout(function() {
				if (xhr.readyState !== 4) {
					timeIsOut = true;
					xhr.abort();
					clearTimeout(timerID)
				}
			}, ajaxOpts.timeout);
			var method = ajaxOpts.method.toUpperCase();
			var str = url + (url.indexOf("?") === -1 ? "?" : "&") + (method === "POST" ? "" : submitStr +
				"&noCache=" + +new Date);
			xhr.open(method, str, ajaxOpts.async);
			xhr.onreadystatechange = function() {
				if (xhr.readyState === 4) {
					if (!timeIsOut && xhr.status === 200) {
						ajaxOpts.onsuccess(xhr)
					} else {
						ajaxOpts.onerror(xhr)
					}
				}
			};
			if (ajaxOpts.headers) {
				for (var key in ajaxOpts.headers) {
					xhr.setRequestHeader(key, ajaxOpts.headers[key])
				}
			}
			if (method === "POST") {
				xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				xhr.send(submitStr)
			} else {
				xhr.send(null)
			}
		}

		function doJsonp(url, opts) {
			var successhandler = opts.onsuccess || function() {},
				scr = document.createElement("SCRIPT"),
				options = opts || {},
				charset = options["charset"],
				callbackField = options["jsonp"] || "callback",
				callbackFnName, timeOut = options["timeOut"] || 0,
				timer, reg = new RegExp("(\\?|&)" + callbackField + "=([^&]*)"),
				matches;
			if (utils.isFunction(successhandler)) {
				callbackFnName = "bd__editor__" + Math.floor(Math.random() * 2147483648).toString(36);
				window[callbackFnName] = getCallBack(0)
			} else if (utils.isString(successhandler)) {
				callbackFnName = successhandler
			} else {
				if (matches = reg.exec(url)) {
					callbackFnName = matches[2]
				}
			}
			url = url.replace(reg, "$1" + callbackField + "=" + callbackFnName);
			if (url.search(reg) < 0) {
				url += (url.indexOf("?") < 0 ? "?" : "&") + callbackField + "=" + callbackFnName
			}
			var queryStr = json2str(opts);
			if (!utils.isEmptyObject(opts.data)) {
				queryStr += (queryStr ? "&" : "") + json2str(opts.data)
			}
			if (queryStr) {
				url = url.replace(/\?/, "?" + queryStr + "&")
			}
			scr.onerror = getCallBack(1);
			if (timeOut) {
				timer = setTimeout(getCallBack(1), timeOut)
			}
			createScriptTag(scr, url, charset);

			function createScriptTag(scr, url, charset) {
				scr.setAttribute("type", "text/javascript");
				scr.setAttribute("defer", "defer");
				charset && scr.setAttribute("charset", charset);
				scr.setAttribute("src", url);
				document.getElementsByTagName("head")[0].appendChild(scr)
			}

			function getCallBack(onTimeOut) {
				return function() {
					try {
						if (onTimeOut) {
							options.onerror && options.onerror()
						} else {
							try {
								clearTimeout(timer);
								successhandler.apply(window, arguments)
							} catch (e) {}
						}
					} catch (exception) {
						options.onerror && options.onerror.call(window, exception)
					} finally {
						options.oncomplete && options.oncomplete.apply(window, arguments);
						scr.parentNode && scr.parentNode.removeChild(scr);
						window[callbackFnName] = null;
						try {
							delete window[callbackFnName]
						} catch (e) {}
					}
				}
			}
		}
		return {
			request: function(url, opts) {
				if (opts && opts.dataType === "jsonp") {
					doJsonp(url, opts)
				} else {
					doAjax(url, opts)
				}
			},
			getJSONP: function(url, data, fn) {
				var opts = {
					data: data,
					oncomplete: fn
				};
				doJsonp(url, opts)
			}
		}
	}();
	UE.api = function() {
		var axios = null;
		! function(e, t) {
			axios = t()
		}(this, function() {
			"use strict";

			function e(t) {
				return e = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) {
					return typeof e
				} : function(e) {
					return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol
						.prototype ? "symbol" : typeof e
				}, e(t)
			}

			function t(e, t) {
				if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function")
			}

			function n(e, t) {
				for (var n = 0; n < t.length; n++) {
					var r = t[n];
					r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !
						0), Object.defineProperty(e, r.key, r)
				}
			}

			function r(e, t, r) {
				return t && n(e.prototype, t), r && n(e, r), Object.defineProperty(e, "prototype", {
					writable: !1
				}), e
			}

			function o(e, t) {
				return function(e) {
					if (Array.isArray(e)) return e
				}(e) || function(e, t) {
					var n = null == e ? null : "undefined" != typeof Symbol && e[Symbol.iterator] || e[
						"@@iterator"];
					if (null == n) return;
					var r, o, i = [],
						a = !0,
						s = !1;
					try {
						for (n = n.call(e); !(a = (r = n.next()).done) && (i.push(r.value), !t || i
								.length !== t); a = !0);
					} catch (e) {
						s = !0, o = e
					} finally {
						try {
							a || null == n.return || n.return()
						} finally {
							if (s) throw o
						}
					}
					return i
				}(e, t) || function(e, t) {
					if (!e) return;
					if ("string" == typeof e) return i(e, t);
					var n = Object.prototype.toString.call(e).slice(8, -1);
					"Object" === n && e.constructor && (n = e.constructor.name);
					if ("Map" === n || "Set" === n) return Array.from(e);
					if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
					return i(e, t)
				}(e, t) || function() {
					throw new TypeError(
						"Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
						)
				}()
			}

			function i(e, t) {
				(null == t || t > e.length) && (t = e.length);
				for (var n = 0, r = new Array(t); n < t; n++) r[n] = e[n];
				return r
			}

			function a(e, t) {
				return function() {
					return e.apply(t, arguments)
				}
			}
			var s, u = Object.prototype.toString,
				c = Object.getPrototypeOf,
				f = (s = Object.create(null), function(e) {
					var t = u.call(e);
					return s[t] || (s[t] = t.slice(8, -1).toLowerCase())
				}),
				l = function(e) {
					return e = e.toLowerCase(),
						function(t) {
							return f(t) === e
						}
				},
				d = function(t) {
					return function(n) {
						return e(n) === t
					}
				},
				p = Array.isArray,
				h = d("undefined");
			var m = l("ArrayBuffer");
			var y = d("string"),
				v = d("function"),
				b = d("number"),
				g = function(t) {
					return null !== t && "object" === e(t)
				},
				w = function(e) {
					if ("object" !== f(e)) return !1;
					var t = c(e);
					return !(null !== t && t !== Object.prototype && null !== Object.getPrototypeOf(t) ||
						Symbol.toStringTag in e || Symbol.iterator in e)
				},
				E = l("Date"),
				O = l("File"),
				S = l("Blob"),
				R = l("FileList"),
				A = l("URLSearchParams");

			function T(t, n) {
				var r, o, i = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {},
					a = i.allOwnKeys,
					s = void 0 !== a && a;
				if (null != t)
					if ("object" !== e(t) && (t = [t]), p(t))
						for (r = 0, o = t.length; r < o; r++) n.call(null, t[r], r, t);
					else {
						var u, c = s ? Object.getOwnPropertyNames(t) : Object.keys(t),
							f = c.length;
						for (r = 0; r < f; r++) u = c[r], n.call(null, t[u], u, t)
					}
			}

			function j(e, t) {
				t = t.toLowerCase();
				for (var n, r = Object.keys(e), o = r.length; o-- > 0;)
					if (t === (n = r[o]).toLowerCase()) return n;
				return null
			}
			var N = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self :
				"undefined" != typeof window ? window : global,
				C = function(e) {
					return !h(e) && e !== N
				};
			var x, P = (x = "undefined" != typeof Uint8Array && c(Uint8Array), function(e) {
					return x && e instanceof x
				}),
				k = l("HTMLFormElement"),
				U = function(e) {
					var t = Object.prototype.hasOwnProperty;
					return function(e, n) {
						return t.call(e, n)
					}
				}(),
				_ = l("RegExp"),
				F = function(e, t) {
					var n = Object.getOwnPropertyDescriptors(e),
						r = {};
					T(n, function(n, o) {
						!1 !== t(n, o, e) && (r[o] = n)
					}), Object.defineProperties(e, r)
				},
				B = "abcdefghijklmnopqrstuvwxyz",
				L = "0123456789",
				D = {
					DIGIT: L,
					ALPHA: B,
					ALPHA_DIGIT: B + B.toUpperCase() + L
				};
			var I = l("AsyncFunction"),
				q = {
					isArray: p,
					isArrayBuffer: m,
					isBuffer: function(e) {
						return null !== e && !h(e) && null !== e.constructor && !h(e.constructor) && v(e
							.constructor.isBuffer) && e.constructor.isBuffer(e)
					},
					isFormData: function(e) {
						var t;
						return e && ("function" == typeof FormData && e instanceof FormData || v(e
							.append) && ("formdata" === (t = f(e)) || "object" === t && v(e
							.toString) && "[object FormData]" === e.toString()))
					},
					isArrayBufferView: function(e) {
						return "undefined" != typeof ArrayBuffer && ArrayBuffer.isView ? ArrayBuffer
							.isView(e) : e && e.buffer && m(e.buffer)
					},
					isString: y,
					isNumber: b,
					isBoolean: function(e) {
						return !0 === e || !1 === e
					},
					isObject: g,
					isPlainObject: w,
					isUndefined: h,
					isDate: E,
					isFile: O,
					isBlob: S,
					isRegExp: _,
					isFunction: v,
					isStream: function(e) {
						return g(e) && v(e.pipe)
					},
					isURLSearchParams: A,
					isTypedArray: P,
					isFileList: R,
					forEach: T,
					merge: function e() {
						for (var t = C(this) && this || {}, n = t.caseless, r = {}, o = function(t, o) {
								var i = n && j(r, o) || o;
								w(r[i]) && w(t) ? r[i] = e(r[i], t) : w(t) ? r[i] = e({}, t) : p(
									t) ? r[i] = t.slice() : r[i] = t
							}, i = 0, a = arguments.length; i < a; i++) arguments[i] && T(arguments[i],
							o);
						return r
					},
					extend: function(e, t, n) {
						var r = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {},
							o = r.allOwnKeys;
						return T(t, function(t, r) {
							n && v(t) ? e[r] = a(t, n) : e[r] = t
						}, {
							allOwnKeys: o
						}), e
					},
					trim: function(e) {
						return e.trim ? e.trim() : e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "")
					},
					stripBOM: function(e) {
						return 65279 === e.charCodeAt(0) && (e = e.slice(1)), e
					},
					inherits: function(e, t, n, r) {
						e.prototype = Object.create(t.prototype, r), e.prototype.constructor = e, Object
							.defineProperty(e, "super", {
								value: t.prototype
							}), n && Object.assign(e.prototype, n)
					},
					toFlatObject: function(e, t, n, r) {
						var o, i, a, s = {};
						if (t = t || {}, null == e) return t;
						do {
							for (i = (o = Object.getOwnPropertyNames(e)).length; i-- > 0;) a = o[i],
								r && !r(a, e, t) || s[a] || (t[a] = e[a], s[a] = !0);
							e = !1 !== n && c(e)
						} while (e && (!n || n(e, t)) && e !== Object.prototype);
						return t
					},
					kindOf: f,
					kindOfTest: l,
					endsWith: function(e, t, n) {
						e = String(e), (void 0 === n || n > e.length) && (n = e.length), n -= t.length;
						var r = e.indexOf(t, n);
						return -1 !== r && r === n
					},
					toArray: function(e) {
						if (!e) return null;
						if (p(e)) return e;
						var t = e.length;
						if (!b(t)) return null;
						for (var n = new Array(t); t-- > 0;) n[t] = e[t];
						return n
					},
					forEachEntry: function(e, t) {
						for (var n, r = (e && e[Symbol.iterator]).call(e);
							(n = r.next()) && !n.done;) {
							var o = n.value;
							t.call(e, o[0], o[1])
						}
					},
					matchAll: function(e, t) {
						for (var n, r = []; null !== (n = e.exec(t));) r.push(n);
						return r
					},
					isHTMLForm: k,
					hasOwnProperty: U,
					hasOwnProp: U,
					reduceDescriptors: F,
					freezeMethods: function(e) {
						F(e, function(t, n) {
							if (v(e) && -1 !== ["arguments", "caller", "callee"].indexOf(n))
								return !1;
							var r = e[n];
							v(r) && (t.enumerable = !1, "writable" in t ? t.writable = !1 : t
								.set || (t.set = function() {
									throw Error("Can not rewrite read-only method '" +
										n + "'")
								}))
						})
					},
					toObjectSet: function(e, t) {
						var n = {},
							r = function(e) {
								e.forEach(function(e) {
									n[e] = !0
								})
							};
						return p(e) ? r(e) : r(String(e).split(t)), n
					},
					toCamelCase: function(e) {
						return e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g, function(e, t, n) {
							return t.toUpperCase() + n
						})
					},
					noop: function() {},
					toFiniteNumber: function(e, t) {
						return e = +e, Number.isFinite(e) ? e : t
					},
					findKey: j,
					global: N,
					isContextDefined: C,
					ALPHABET: D,
					generateString: function() {
						for (var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] :
								16, t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] :
								D.ALPHA_DIGIT, n = "", r = t.length; e--;) n += t[Math.random() * r |
						0];
						return n
					},
					isSpecCompliantForm: function(e) {
						return !!(e && v(e.append) && "FormData" === e[Symbol.toStringTag] && e[Symbol
							.iterator])
					},
					toJSONObject: function(e) {
						var t = new Array(10);
						return function e(n, r) {
							if (g(n)) {
								if (t.indexOf(n) >= 0) return;
								if (!("toJSON" in n)) {
									t[r] = n;
									var o = p(n) ? [] : {};
									return T(n, function(t, n) {
										var i = e(t, r + 1);
										!h(i) && (o[n] = i)
									}), t[r] = void 0, o
								}
							}
							return n
						}(e, 0)
					},
					isAsyncFn: I,
					isThenable: function(e) {
						return e && (g(e) || v(e)) && v(e.then) && v(e.catch)
					}
				};

			function M(e, t, n, r, o) {
				Error.call(this), Error.captureStackTrace ? Error.captureStackTrace(this, this
					.constructor) : this.stack = (new Error).stack, this.message = e, this.name =
					"AxiosError", t && (this.code = t), n && (this.config = n), r && (this.request = r),
					o && (this.response = o)
			}
			q.inherits(M, Error, {
				toJSON: function() {
					return {
						message: this.message,
						name: this.name,
						description: this.description,
						number: this.number,
						fileName: this.fileName,
						lineNumber: this.lineNumber,
						columnNumber: this.columnNumber,
						stack: this.stack,
						config: q.toJSONObject(this.config),
						code: this.code,
						status: this.response && this.response.status ? this.response.status :
							null
					}
				}
			});
			var z = M.prototype,
				H = {};
			["ERR_BAD_OPTION_VALUE", "ERR_BAD_OPTION", "ECONNABORTED", "ETIMEDOUT", "ERR_NETWORK",
				"ERR_FR_TOO_MANY_REDIRECTS", "ERR_DEPRECATED", "ERR_BAD_RESPONSE", "ERR_BAD_REQUEST",
				"ERR_CANCELED", "ERR_NOT_SUPPORT", "ERR_INVALID_URL"
			].forEach(function(e) {
				H[e] = {
					value: e
				}
			}), Object.defineProperties(M, H), Object.defineProperty(z, "isAxiosError", {
				value: !0
			}), M.from = function(e, t, n, r, o, i) {
				var a = Object.create(z);
				return q.toFlatObject(e, a, function(e) {
						return e !== Error.prototype
					}, function(e) {
						return "isAxiosError" !== e
					}), M.call(a, e.message, t, n, r, o), a.cause = e, a.name = e.name, i && Object
					.assign(a, i), a
			};

			function J(e) {
				return q.isPlainObject(e) || q.isArray(e)
			}

			function W(e) {
				return q.endsWith(e, "[]") ? e.slice(0, -2) : e
			}

			function K(e, t, n) {
				return e ? e.concat(t).map(function(e, t) {
					return e = W(e), !n && t ? "[" + e + "]" : e
				}).join(n ? "." : "") : t
			}
			var V = q.toFlatObject(q, {}, null, function(e) {
				return /^is[A-Z]/.test(e)
			});

			function G(t, n, r) {
				if (!q.isObject(t)) throw new TypeError("target must be an object");
				n = n || new FormData;
				var o = (r = q.toFlatObject(r, {
						metaTokens: !0,
						dots: !1,
						indexes: !1
					}, !1, function(e, t) {
						return !q.isUndefined(t[e])
					})).metaTokens,
					i = r.visitor || f,
					a = r.dots,
					s = r.indexes,
					u = (r.Blob || "undefined" != typeof Blob && Blob) && q.isSpecCompliantForm(n);
				if (!q.isFunction(i)) throw new TypeError("visitor must be a function");

				function c(e) {
					if (null === e) return "";
					if (q.isDate(e)) return e.toISOString();
					if (!u && q.isBlob(e)) throw new M("Blob is not supported. Use a Buffer instead.");
					return q.isArrayBuffer(e) || q.isTypedArray(e) ? u && "function" == typeof Blob ?
						new Blob([e]) : Buffer.from(e) : e
				}

				function f(t, r, i) {
					var u = t;
					if (t && !i && "object" === e(t))
						if (q.endsWith(r, "{}")) r = o ? r : r.slice(0, -2), t = JSON.stringify(t);
						else if (q.isArray(t) && function(e) {
							return q.isArray(e) && !e.some(J)
						}(t) || (q.isFileList(t) || q.endsWith(r, "[]")) && (u = q.toArray(t))) return r =
						W(r), u.forEach(function(e, t) {
							!q.isUndefined(e) && null !== e && n.append(!0 === s ? K([r], t, a) :
								null === s ? r : r + "[]", c(e))
						}), !1;
					return !!J(t) || (n.append(K(i, r, a), c(t)), !1)
				}
				var l = [],
					d = Object.assign(V, {
						defaultVisitor: f,
						convertValue: c,
						isVisitable: J
					});
				if (!q.isObject(t)) throw new TypeError("data must be an object");
				return function e(t, r) {
					if (!q.isUndefined(t)) {
						if (-1 !== l.indexOf(t)) throw Error("Circular reference detected in " + r.join(
							"."));
						l.push(t), q.forEach(t, function(t, o) {
							!0 === (!(q.isUndefined(t) || null === t) && i.call(n, t, q
								.isString(o) ? o.trim() : o, r, d)) && e(t, r ? r.concat(
								o) : [o])
						}), l.pop()
					}
				}(t), n
			}

			function $(e) {
				var t = {
					"!": "%21",
					"'": "%27",
					"(": "%28",
					")": "%29",
					"~": "%7E",
					"%20": "+",
					"%00": "\0"
				};
				return encodeURIComponent(e).replace(/[!'()~]|%20|%00/g, function(e) {
					return t[e]
				})
			}

			function X(e, t) {
				this._pairs = [], e && G(e, this, t)
			}
			var Q = X.prototype;

			function Z(e) {
				return encodeURIComponent(e).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi,
					",").replace(/%20/g, "+").replace(/%5B/gi, "[").replace(/%5D/gi, "]")
			}

			function Y(e, t, n) {
				if (!t) return e;
				var r, o = n && n.encode || Z,
					i = n && n.serialize;
				if (r = i ? i(t, n) : q.isURLSearchParams(t) ? t.toString() : new X(t, n).toString(o)) {
					var a = e.indexOf("#"); - 1 !== a && (e = e.slice(0, a)), e += (-1 === e.indexOf("?") ?
						"?" : "&") + r
				}
				return e
			}
			Q.append = function(e, t) {
				this._pairs.push([e, t])
			}, Q.toString = function(e) {
				var t = e ? function(t) {
					return e.call(this, t, $)
				} : $;
				return this._pairs.map(function(e) {
					return t(e[0]) + "=" + t(e[1])
				}, "").join("&")
			};
			var ee, te = function() {
					function e() {
						t(this, e), this.handlers = []
					}
					return r(e, [{
						key: "use",
						value: function(e, t, n) {
							return this.handlers.push({
								fulfilled: e,
								rejected: t,
								synchronous: !!n && n.synchronous,
								runWhen: n ? n.runWhen : null
							}), this.handlers.length - 1
						}
					}, {
						key: "eject",
						value: function(e) {
							this.handlers[e] && (this.handlers[e] = null)
						}
					}, {
						key: "clear",
						value: function() {
							this.handlers && (this.handlers = [])
						}
					}, {
						key: "forEach",
						value: function(e) {
							q.forEach(this.handlers, function(t) {
								null !== t && e(t)
							})
						}
					}]), e
				}(),
				ne = {
					silentJSONParsing: !0,
					forcedJSONParsing: !0,
					clarifyTimeoutError: !1
				},
				re = {
					isBrowser: !0,
					classes: {
						URLSearchParams: "undefined" != typeof URLSearchParams ? URLSearchParams : X,
						FormData: "undefined" != typeof FormData ? FormData : null,
						Blob: "undefined" != typeof Blob ? Blob : null
					},
					isStandardBrowserEnv: ("undefined" == typeof navigator || "ReactNative" !== (ee =
							navigator.product) && "NativeScript" !== ee && "NS" !== ee) && "undefined" !=
						typeof window && "undefined" != typeof document,
					isStandardBrowserWebWorkerEnv: "undefined" != typeof WorkerGlobalScope &&
						self instanceof WorkerGlobalScope && "function" == typeof self.importScripts,
					protocols: ["http", "https", "file", "blob", "url", "data"]
				};

			function oe(e) {
				function t(e, n, r, o) {
					var i = e[o++],
						a = Number.isFinite(+i),
						s = o >= e.length;
					return i = !i && q.isArray(r) ? r.length : i, s ? (q.hasOwnProp(r, i) ? r[i] = [r[i],
						n] : r[i] = n, !a) : (r[i] && q.isObject(r[i]) || (r[i] = []), t(e, n, r[i],
						o) && q.isArray(r[i]) && (r[i] = function(e) {
							var t, n, r = {},
								o = Object.keys(e),
								i = o.length;
							for (t = 0; t < i; t++) r[n = o[t]] = e[n];
							return r
						}(r[i])), !a)
				}
				if (q.isFormData(e) && q.isFunction(e.entries)) {
					var n = {};
					return q.forEachEntry(e, function(e, r) {
						t(function(e) {
							return q.matchAll(/\w+|\[(\w*)]/g, e).map(function(e) {
								return "[]" === e[0] ? "" : e[1] || e[0]
							})
						}(e), r, n, 0)
					}), n
				}
				return null
			}
			var ie = {
				"Content-Type": void 0
			};
			var ae = {
				transitional: ne,
				adapter: ["xhr", "http"],
				transformRequest: [function(e, t) {
					var n, r = t.getContentType() || "",
						o = r.indexOf("application/json") > -1,
						i = q.isObject(e);
					if (i && q.isHTMLForm(e) && (e = new FormData(e)), q.isFormData(e))
					return o && o ? JSON.stringify(oe(e)) : e;
					if (q.isArrayBuffer(e) || q.isBuffer(e) || q.isStream(e) || q.isFile(e) || q
						.isBlob(e)) return e;
					if (q.isArrayBufferView(e)) return e.buffer;
					if (q.isURLSearchParams(e)) return t.setContentType(
							"application/x-www-form-urlencoded;charset=utf-8", !1), e
						.toString();
					if (i) {
						if (r.indexOf("application/x-www-form-urlencoded") > -1)
						return function(e, t) {
								return G(e, new re.classes.URLSearchParams, Object.assign({
									visitor: function(e, t, n, r) {
										return re.isNode && q.isBuffer(e) ?
											(this.append(t, e.toString(
												"base64")), !1) : r
											.defaultVisitor.apply(this,
												arguments)
									}
								}, t))
							}(e, this.formSerializer).toString();
						if ((n = q.isFileList(e)) || r.indexOf("multipart/form-data") > -1) {
							var a = this.env && this.env.FormData;
							return G(n ? {
								"files[]": e
							} : e, a && new a, this.formSerializer)
						}
					}
					return i || o ? (t.setContentType("application/json", !1), function(e, t,
					n) {
						if (q.isString(e)) try {
							return (t || JSON.parse)(e), q.trim(e)
						} catch (e) {
							if ("SyntaxError" !== e.name) throw e
						}
						return (n || JSON.stringify)(e)
					}(e)) : e
				}],
				transformResponse: [function(e) {
					var t = this.transitional || ae.transitional,
						n = t && t.forcedJSONParsing,
						r = "json" === this.responseType;
					if (e && q.isString(e) && (n && !this.responseType || r)) {
						var o = !(t && t.silentJSONParsing) && r;
						try {
							return JSON.parse(e)
						} catch (e) {
							if (o) {
								if ("SyntaxError" === e.name) throw M.from(e, M
									.ERR_BAD_RESPONSE, this, null, this.response);
								throw e
							}
						}
					}
					return e
				}],
				timeout: 0,
				xsrfCookieName: "XSRF-TOKEN",
				xsrfHeaderName: "X-XSRF-TOKEN",
				maxContentLength: -1,
				maxBodyLength: -1,
				env: {
					FormData: re.classes.FormData,
					Blob: re.classes.Blob
				},
				validateStatus: function(e) {
					return e >= 200 && e < 300
				},
				headers: {
					common: {
						Accept: "application/json, text/plain, */*"
					}
				}
			};
			q.forEach(["delete", "get", "head"], function(e) {
				ae.headers[e] = {}
			}), q.forEach(["post", "put", "patch"], function(e) {
				ae.headers[e] = q.merge(ie)
			});
			var se = ae,
				ue = q.toObjectSet(["age", "authorization", "content-length", "content-type", "etag",
					"expires", "from", "host", "if-modified-since", "if-unmodified-since",
					"last-modified", "location", "max-forwards", "proxy-authorization", "referer",
					"retry-after", "user-agent"
				]),
				ce = Symbol("internals");

			function fe(e) {
				return e && String(e).trim().toLowerCase()
			}

			function le(e) {
				return !1 === e || null == e ? e : q.isArray(e) ? e.map(le) : String(e)
			}

			function de(e, t, n, r, o) {
				return q.isFunction(r) ? r.call(this, t, n) : (o && (t = n), q.isString(t) ? q.isString(r) ?
					-1 !== t.indexOf(r) : q.isRegExp(r) ? r.test(t) : void 0 : void 0)
			}
			var pe = function(e, n) {
				function i(e) {
					t(this, i), e && this.set(e)
				}
				return r(i, [{
					key: "set",
					value: function(e, t, n) {
						var r = this;

						function o(e, t, n) {
							var o = fe(t);
							if (!o) throw new Error(
								"header name must be a non-empty string");
							var i = q.findKey(r, o);
							(!i || void 0 === r[i] || !0 === n || void 0 === n && !1 !==
								r[i]) && (r[i || t] = le(e))
						}
						var i, a, s, u, c, f = function(e, t) {
							return q.forEach(e, function(e, n) {
								return o(e, n, t)
							})
						};
						return q.isPlainObject(e) || e instanceof this.constructor ? f(
								e, t) : q.isString(e) && (e = e.trim()) && !
							/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim()) ? f((c = {},
								(i = e) && i.split("\n").forEach(function(e) {
									u = e.indexOf(":"), a = e.substring(0, u)
										.trim().toLowerCase(), s = e.substring(
											u + 1).trim(), !a || c[a] && ue[
										a] || ("set-cookie" === a ? c[a] ? c[a]
											.push(s) : c[a] = [s] : c[a] = c[
											a] ? c[a] + ", " + s : s)
								}), c), t) : null != e && o(t, e, n), this
					}
				}, {
					key: "get",
					value: function(e, t) {
						if (e = fe(e)) {
							var n = q.findKey(this, e);
							if (n) {
								var r = this[n];
								if (!t) return r;
								if (!0 === t) return function(e) {
									for (var t, n = Object.create(null), r =
											/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g; t =
										r.exec(e);) n[t[1]] = t[2];
									return n
								}(r);
								if (q.isFunction(t)) return t.call(this, r, n);
								if (q.isRegExp(t)) return t.exec(r);
								throw new TypeError(
									"parser must be boolean|regexp|function")
							}
						}
					}
				}, {
					key: "has",
					value: function(e, t) {
						if (e = fe(e)) {
							var n = q.findKey(this, e);
							return !(!n || void 0 === this[n] || t && !de(0, this[n], n,
								t))
						}
						return !1
					}
				}, {
					key: "delete",
					value: function(e, t) {
						var n = this,
							r = !1;

						function o(e) {
							if (e = fe(e)) {
								var o = q.findKey(n, e);
								!o || t && !de(0, n[o], o, t) || (delete n[o], r = !0)
							}
						}
						return q.isArray(e) ? e.forEach(o) : o(e), r
					}
				}, {
					key: "clear",
					value: function(e) {
						for (var t = Object.keys(this), n = t.length, r = !1; n--;) {
							var o = t[n];
							e && !de(0, this[o], o, e, !0) || (delete this[o], r = !0)
						}
						return r
					}
				}, {
					key: "normalize",
					value: function(e) {
						var t = this,
							n = {};
						return q.forEach(this, function(r, o) {
							var i = q.findKey(n, o);
							if (i) return t[i] = le(r), void delete t[o];
							var a = e ? function(e) {
								return e.trim().toLowerCase().replace(
									/([a-z\d])(\w*)/g,
									function(e, t, n) {
										return t.toUpperCase() + n
									})
							}(o) : String(o).trim();
							a !== o && delete t[o], t[a] = le(r), n[a] = !0
						}), this
					}
				}, {
					key: "concat",
					value: function() {
						for (var e, t = arguments.length, n = new Array(t), r = 0; r <
							t; r++) n[r] = arguments[r];
						return (e = this.constructor).concat.apply(e, [this].concat(n))
					}
				}, {
					key: "toJSON",
					value: function(e) {
						var t = Object.create(null);
						return q.forEach(this, function(n, r) {
							null != n && !1 !== n && (t[r] = e && q.isArray(n) ?
								n.join(", ") : n)
						}), t
					}
				}, {
					key: Symbol.iterator,
					value: function() {
						return Object.entries(this.toJSON())[Symbol.iterator]()
					}
				}, {
					key: "toString",
					value: function() {
						return Object.entries(this.toJSON()).map(function(e) {
							var t = o(e, 2);
							return t[0] + ": " + t[1]
						}).join("\n")
					}
				}, {
					key: Symbol.toStringTag,
					get: function() {
						return "AxiosHeaders"
					}
				}], [{
					key: "from",
					value: function(e) {
						return e instanceof this ? e : new this(e)
					}
				}, {
					key: "concat",
					value: function(e) {
						for (var t = new this(e), n = arguments.length, r = new Array(
								n > 1 ? n - 1 : 0), o = 1; o < n; o++) r[o - 1] =
							arguments[o];
						return r.forEach(function(e) {
							return t.set(e)
						}), t
					}
				}, {
					key: "accessor",
					value: function(e) {
						var t = (this[ce] = this[ce] = {
								accessors: {}
							}).accessors,
							n = this.prototype;

						function r(e) {
							var r = fe(e);
							t[r] || (! function(e, t) {
								var n = q.toCamelCase(" " + t);
								["get", "set", "has"].forEach(function(r) {
									Object.defineProperty(e, r + n, {
										value: function(e, n,
										o) {
											return this[r]
												.call(this,
													t, e, n,
													o)
										},
										configurable: !0
									})
								})
							}(n, e), t[r] = !0)
						}
						return q.isArray(e) ? e.forEach(r) : r(e), this
					}
				}]), i
			}();
			pe.accessor(["Content-Type", "Content-Length", "Accept", "Accept-Encoding", "User-Agent",
				"Authorization"
			]), q.freezeMethods(pe.prototype), q.freezeMethods(pe);
			var he = pe;

			function me(e, t) {
				var n = this || se,
					r = t || n,
					o = he.from(r.headers),
					i = r.data;
				return q.forEach(e, function(e) {
					i = e.call(n, i, o.normalize(), t ? t.status : void 0)
				}), o.normalize(), i
			}

			function ye(e) {
				return !(!e || !e.__CANCEL__)
			}

			function ve(e, t, n) {
				M.call(this, null == e ? "canceled" : e, M.ERR_CANCELED, t, n), this.name = "CanceledError"
			}
			q.inherits(ve, M, {
				__CANCEL__: !0
			});
			var be = re.isStandardBrowserEnv ? {
				write: function(e, t, n, r, o, i) {
					var a = [];
					a.push(e + "=" + encodeURIComponent(t)), q.isNumber(n) && a.push("expires=" +
							new Date(n).toGMTString()), q.isString(r) && a.push("path=" + r), q
						.isString(o) && a.push("domain=" + o), !0 === i && a.push("secure"),
						document.cookie = a.join("; ")
				},
				read: function(e) {
					var t = document.cookie.match(new RegExp("(^|;\\s*)(" + e + ")=([^;]*)"));
					return t ? decodeURIComponent(t[3]) : null
				},
				remove: function(e) {
					this.write(e, "", Date.now() - 864e5)
				}
			} : {
				write: function() {},
				read: function() {
					return null
				},
				remove: function() {}
			};

			function ge(e, t) {
				return e && !/^([a-z][a-z\d+\-.]*:)?\/\//i.test(t) ? function(e, t) {
					return t ? e.replace(/\/+$/, "") + "/" + t.replace(/^\/+/, "") : e
				}(e, t) : t
			}
			var we = re.isStandardBrowserEnv ? function() {
				var e, t = /(msie|trident)/i.test(navigator.userAgent),
					n = document.createElement("a");

				function r(e) {
					var r = e;
					return t && (n.setAttribute("href", r), r = n.href), n.setAttribute("href", r), {
						href: n.href,
						protocol: n.protocol ? n.protocol.replace(/:$/, "") : "",
						host: n.host,
						search: n.search ? n.search.replace(/^\?/, "") : "",
						hash: n.hash ? n.hash.replace(/^#/, "") : "",
						hostname: n.hostname,
						port: n.port,
						pathname: "/" === n.pathname.charAt(0) ? n.pathname : "/" + n.pathname
					}
				}
				return e = r(window.location.href),
					function(t) {
						var n = q.isString(t) ? r(t) : t;
						return n.protocol === e.protocol && n.host === e.host
					}
			}() : function() {
				return !0
			};

			function Ee(e, t) {
				var n = 0,
					r = function(e, t) {
						e = e || 10;
						var n, r = new Array(e),
							o = new Array(e),
							i = 0,
							a = 0;
						return t = void 0 !== t ? t : 1e3,
							function(s) {
								var u = Date.now(),
									c = o[a];
								n || (n = u), r[i] = s, o[i] = u;
								for (var f = a, l = 0; f !== i;) l += r[f++], f %= e;
								if ((i = (i + 1) % e) === a && (a = (a + 1) % e), !(u - n < t)) {
									var d = c && u - c;
									return d ? Math.round(1e3 * l / d) : void 0
								}
							}
					}(50, 250);
				return function(o) {
					var i = o.loaded,
						a = o.lengthComputable ? o.total : void 0,
						s = i - n,
						u = r(s);
					n = i;
					var c = {
						loaded: i,
						total: a,
						progress: a ? i / a : void 0,
						bytes: s,
						rate: u || void 0,
						estimated: u && a && i <= a ? (a - i) / u : void 0,
						event: o
					};
					c[t ? "download" : "upload"] = !0, e(c)
				}
			}
			var Oe = {
				http: null,
				xhr: "undefined" != typeof XMLHttpRequest && function(e) {
					return new Promise(function(t, n) {
						var r, o = e.data,
							i = he.from(e.headers).normalize(),
							a = e.responseType;

						function s() {
							e.cancelToken && e.cancelToken.unsubscribe(r), e.signal && e
								.signal.removeEventListener("abort", r)
						}
						q.isFormData(o) && (re.isStandardBrowserEnv || re
							.isStandardBrowserWebWorkerEnv ? i.setContentType(!1) : i
							.setContentType("multipart/form-data;", !1));
						var u = new XMLHttpRequest;
						if (e.auth) {
							var c = e.auth.username || "",
								f = e.auth.password ? unescape(encodeURIComponent(e.auth
									.password)) : "";
							i.set("Authorization", "Basic " + btoa(c + ":" + f))
						}
						var l = ge(e.baseURL, e.url);

						function d() {
							if (u) {
								var r = he.from("getAllResponseHeaders" in u && u
									.getAllResponseHeaders());
								! function(e, t, n) {
									var r = n.config.validateStatus;
									n.status && r && !r(n.status) ? t(new M(
										"Request failed with status code " + n
										.status, [M.ERR_BAD_REQUEST, M
											.ERR_BAD_RESPONSE
										][Math.floor(n.status / 100) - 4], n.config,
										n.request, n)) : e(n)
								}(function(e) {
									t(e), s()
								}, function(e) {
									n(e), s()
								}, {
									data: a && "text" !== a && "json" !== a ? u
										.response : u.responseText,
									status: u.status,
									statusText: u.statusText,
									headers: r,
									config: e,
									request: u
								}), u = null
							}
						}
						if (u.open(e.method.toUpperCase(), Y(l, e.params, e
								.paramsSerializer), !0), u.timeout = e.timeout,
							"onloadend" in u ? u.onloadend = d : u.onreadystatechange =
							function() {
								u && 4 === u.readyState && (0 !== u.status || u
									.responseURL && 0 === u.responseURL.indexOf("file:")
									) && setTimeout(d)
							}, u.onabort = function() {
								u && (n(new M("Request aborted", M.ECONNABORTED, e, u)), u =
									null)
							}, u.onerror = function() {
								n(new M("Network Error", M.ERR_NETWORK, e, u)), u = null
							}, u.ontimeout = function() {
								var t = e.timeout ? "timeout of " + e.timeout +
									"ms exceeded" : "timeout exceeded",
									r = e.transitional || ne;
								e.timeoutErrorMessage && (t = e.timeoutErrorMessage), n(
									new M(t, r.clarifyTimeoutError ? M.ETIMEDOUT : M
										.ECONNABORTED, e, u)), u = null
							}, re.isStandardBrowserEnv) {
							var p = (e.withCredentials || we(l)) && e.xsrfCookieName && be
								.read(e.xsrfCookieName);
							p && i.set(e.xsrfHeaderName, p)
						}
						void 0 === o && i.setContentType(null), "setRequestHeader" in u && q
							.forEach(i.toJSON(), function(e, t) {
								u.setRequestHeader(t, e)
							}), q.isUndefined(e.withCredentials) || (u.withCredentials = !!e
								.withCredentials), a && "json" !== a && (u.responseType = e
								.responseType), "function" == typeof e.onDownloadProgress &&
							u.addEventListener("progress", Ee(e.onDownloadProgress, !0)),
							"function" == typeof e.onUploadProgress && u.upload && u.upload
							.addEventListener("progress", Ee(e.onUploadProgress)), (e
								.cancelToken || e.signal) && (r = function(t) {
									u && (n(!t || t.type ? new ve(null, e, u) : t), u
									.abort(), u = null)
								}, e.cancelToken && e.cancelToken.subscribe(r), e.signal &&
								(e.signal.aborted ? r() : e.signal.addEventListener("abort",
									r)));
						var h, m = (h = /^([-+\w]{1,25})(:?\/\/|:)/.exec(l)) && h[1] || "";
						m && -1 === re.protocols.indexOf(m) ? n(new M(
								"Unsupported protocol " + m + ":", M.ERR_BAD_REQUEST, e
								)) : u.send(o || null)
					})
				}
			};
			q.forEach(Oe, function(e, t) {
				if (e) {
					try {
						Object.defineProperty(e, "name", {
							value: t
						})
					} catch (e) {}
					Object.defineProperty(e, "adapterName", {
						value: t
					})
				}
			});
			var Se = function(e) {
				for (var t, n, r = (e = q.isArray(e) ? e : [e]).length, o = 0; o < r && (t = e[o], !(n =
						q.isString(t) ? Oe[t.toLowerCase()] : t)); o++);
				if (!n) {
					if (!1 === n) throw new M("Adapter ".concat(t,
						" is not supported by the environment"), "ERR_NOT_SUPPORT");
					throw new Error(q.hasOwnProp(Oe, t) ? "Adapter '".concat(t,
						"' is not available in the build") : "Unknown adapter '".concat(t, "'"))
				}
				if (!q.isFunction(n)) throw new TypeError("adapter is not a function");
				return n
			};

			function Re(e) {
				if (e.cancelToken && e.cancelToken.throwIfRequested(), e.signal && e.signal.aborted)
				throw new ve(null, e)
			}

			function Ae(e) {
				return Re(e), e.headers = he.from(e.headers), e.data = me.call(e, e.transformRequest), -
					1 !== ["post", "put", "patch"].indexOf(e.method) && e.headers.setContentType(
						"application/x-www-form-urlencoded", !1), Se(e.adapter || se.adapter)(e).then(
						function(t) {
							return Re(e), t.data = me.call(e, e.transformResponse, t), t.headers = he.from(t
								.headers), t
						},
						function(t) {
							return ye(t) || (Re(e), t && t.response && (t.response.data = me.call(e, e
								.transformResponse, t.response), t.response.headers = he.from(t
								.response.headers))), Promise.reject(t)
						})
			}
			var Te = function(e) {
				return e instanceof he ? e.toJSON() : e
			};

			function je(e, t) {
				t = t || {};
				var n = {};

				function r(e, t, n) {
					return q.isPlainObject(e) && q.isPlainObject(t) ? q.merge.call({
						caseless: n
					}, e, t) : q.isPlainObject(t) ? q.merge({}, t) : q.isArray(t) ? t.slice() : t
				}

				function o(e, t, n) {
					return q.isUndefined(t) ? q.isUndefined(e) ? void 0 : r(void 0, e, n) : r(e, t, n)
				}

				function i(e, t) {
					if (!q.isUndefined(t)) return r(void 0, t)
				}

				function a(e, t) {
					return q.isUndefined(t) ? q.isUndefined(e) ? void 0 : r(void 0, e) : r(void 0, t)
				}

				function s(n, o, i) {
					return i in t ? r(n, o) : i in e ? r(void 0, n) : void 0
				}
				var u = {
					url: i,
					method: i,
					data: i,
					baseURL: a,
					transformRequest: a,
					transformResponse: a,
					paramsSerializer: a,
					timeout: a,
					timeoutMessage: a,
					withCredentials: a,
					adapter: a,
					responseType: a,
					xsrfCookieName: a,
					xsrfHeaderName: a,
					onUploadProgress: a,
					onDownloadProgress: a,
					decompress: a,
					maxContentLength: a,
					maxBodyLength: a,
					beforeRedirect: a,
					transport: a,
					httpAgent: a,
					httpsAgent: a,
					cancelToken: a,
					socketPath: a,
					responseEncoding: a,
					validateStatus: s,
					headers: function(e, t) {
						return o(Te(e), Te(t), !0)
					}
				};
				return q.forEach(Object.keys(Object.assign({}, e, t)), function(r) {
					var i = u[r] || o,
						a = i(e[r], t[r], r);
					q.isUndefined(a) && i !== s || (n[r] = a)
				}), n
			}
			var Ne = "1.4.0",
				Ce = {};
			["object", "boolean", "number", "function", "string", "symbol"].forEach(function(t, n) {
				Ce[t] = function(r) {
					return e(r) === t || "a" + (n < 1 ? "n " : " ") + t
				}
			});
			var xe = {};
			Ce.transitional = function(e, t, n) {
				function r(e, t) {
					return "[Axios v1.4.0] Transitional option '" + e + "'" + t + (n ? ". " + n : "")
				}
				return function(n, o, i) {
					if (!1 === e) throw new M(r(o, " has been removed" + (t ? " in " + t : "")), M
						.ERR_DEPRECATED);
					return t && !xe[o] && (xe[o] = !0, console.warn(r(o,
						" has been deprecated since v" + t +
						" and will be removed in the near future"))), !e || e(n, o, i)
				}
			};
			var Pe = {
					assertOptions: function(t, n, r) {
						if ("object" !== e(t)) throw new M("options must be an object", M
							.ERR_BAD_OPTION_VALUE);
						for (var o = Object.keys(t), i = o.length; i-- > 0;) {
							var a = o[i],
								s = n[a];
							if (s) {
								var u = t[a],
									c = void 0 === u || s(u, a, t);
								if (!0 !== c) throw new M("option " + a + " must be " + c, M
									.ERR_BAD_OPTION_VALUE)
							} else if (!0 !== r) throw new M("Unknown option " + a, M.ERR_BAD_OPTION)
						}
					},
					validators: Ce
				},
				ke = Pe.validators,
				Ue = function() {
					function e(n) {
						t(this, e), this.defaults = n, this.interceptors = {
							request: new te,
							response: new te
						}
					}
					return r(e, [{
						key: "request",
						value: function(e, t) {
							"string" == typeof e ? (t = t || {}).url = e : t = e || {};
							var n, r = t = je(this.defaults, t),
								o = r.transitional,
								i = r.paramsSerializer,
								a = r.headers;
							void 0 !== o && Pe.assertOptions(o, {
								silentJSONParsing: ke.transitional(ke.boolean),
								forcedJSONParsing: ke.transitional(ke.boolean),
								clarifyTimeoutError: ke.transitional(ke.boolean)
							}, !1), null != i && (q.isFunction(i) ? t
							.paramsSerializer = {
								serialize: i
							} : Pe.assertOptions(i, {
								encode: ke.function,
								serialize: ke.function
							}, !0)), t.method = (t.method || this.defaults.method ||
								"get").toLowerCase(), (n = a && q.merge(a.common, a[t
								.method])) && q.forEach(["delete", "get", "head",
								"post", "put", "patch", "common"
							], function(e) {
								delete a[e]
							}), t.headers = he.concat(n, a);
							var s = [],
								u = !0;
							this.interceptors.request.forEach(function(e) {
								"function" == typeof e.runWhen && !1 === e.runWhen(
									t) || (u = u && e.synchronous, s.unshift(e
									.fulfilled, e.rejected))
							});
							var c, f = [];
							this.interceptors.response.forEach(function(e) {
								f.push(e.fulfilled, e.rejected)
							});
							var l, d = 0;
							if (!u) {
								var p = [Ae.bind(this), void 0];
								for (p.unshift.apply(p, s), p.push.apply(p, f), l = p
									.length, c = Promise.resolve(t); d < l;) c = c.then(p[
									d++], p[d++]);
								return c
							}
							l = s.length;
							var h = t;
							for (d = 0; d < l;) {
								var m = s[d++],
									y = s[d++];
								try {
									h = m(h)
								} catch (e) {
									y.call(this, e);
									break
								}
							}
							try {
								c = Ae.call(this, h)
							} catch (e) {
								return Promise.reject(e)
							}
							for (d = 0, l = f.length; d < l;) c = c.then(f[d++], f[d++]);
							return c
						}
					}, {
						key: "getUri",
						value: function(e) {
							return Y(ge((e = je(this.defaults, e)).baseURL, e.url), e
								.params, e.paramsSerializer)
						}
					}]), e
				}();
			q.forEach(["delete", "get", "head", "options"], function(e) {
				Ue.prototype[e] = function(t, n) {
					return this.request(je(n || {}, {
						method: e,
						url: t,
						data: (n || {}).data
					}))
				}
			}), q.forEach(["post", "put", "patch"], function(e) {
				function t(t) {
					return function(n, r, o) {
						return this.request(je(o || {}, {
							method: e,
							headers: t ? {
								"Content-Type": "multipart/form-data"
							} : {},
							url: n,
							data: r
						}))
					}
				}
				Ue.prototype[e] = t(), Ue.prototype[e + "Form"] = t(!0)
			});
			var _e = Ue,
				Fe = function() {
					function e(n) {
						if (t(this, e), "function" != typeof n) throw new TypeError(
							"executor must be a function.");
						var r;
						this.promise = new Promise(function(e) {
							r = e
						});
						var o = this;
						this.promise.then(function(e) {
							if (o._listeners) {
								for (var t = o._listeners.length; t-- > 0;) o._listeners[t](e);
								o._listeners = null
							}
						}), this.promise.then = function(e) {
							var t, n = new Promise(function(e) {
								o.subscribe(e), t = e
							}).then(e);
							return n.cancel = function() {
								o.unsubscribe(t)
							}, n
						}, n(function(e, t, n) {
							o.reason || (o.reason = new ve(e, t, n), r(o.reason))
						})
					}
					return r(e, [{
						key: "throwIfRequested",
						value: function() {
							if (this.reason) throw this.reason
						}
					}, {
						key: "subscribe",
						value: function(e) {
							this.reason ? e(this.reason) : this._listeners ? this._listeners
								.push(e) : this._listeners = [e]
						}
					}, {
						key: "unsubscribe",
						value: function(e) {
							if (this._listeners) {
								var t = this._listeners.indexOf(e); - 1 !== t && this
									._listeners.splice(t, 1)
							}
						}
					}], [{
						key: "source",
						value: function() {
							var t;
							return {
								token: new e(function(e) {
									t = e
								}),
								cancel: t
							}
						}
					}]), e
				}();
			var Be = {
				Continue: 100,
				SwitchingProtocols: 101,
				Processing: 102,
				EarlyHints: 103,
				Ok: 200,
				Created: 201,
				Accepted: 202,
				NonAuthoritativeInformation: 203,
				NoContent: 204,
				ResetContent: 205,
				PartialContent: 206,
				MultiStatus: 207,
				AlreadyReported: 208,
				ImUsed: 226,
				MultipleChoices: 300,
				MovedPermanently: 301,
				Found: 302,
				SeeOther: 303,
				NotModified: 304,
				UseProxy: 305,
				Unused: 306,
				TemporaryRedirect: 307,
				PermanentRedirect: 308,
				BadRequest: 400,
				Unauthorized: 401,
				PaymentRequired: 402,
				Forbidden: 403,
				NotFound: 404,
				MethodNotAllowed: 405,
				NotAcceptable: 406,
				ProxyAuthenticationRequired: 407,
				RequestTimeout: 408,
				Conflict: 409,
				Gone: 410,
				LengthRequired: 411,
				PreconditionFailed: 412,
				PayloadTooLarge: 413,
				UriTooLong: 414,
				UnsupportedMediaType: 415,
				RangeNotSatisfiable: 416,
				ExpectationFailed: 417,
				ImATeapot: 418,
				MisdirectedRequest: 421,
				UnprocessableEntity: 422,
				Locked: 423,
				FailedDependency: 424,
				TooEarly: 425,
				UpgradeRequired: 426,
				PreconditionRequired: 428,
				TooManyRequests: 429,
				RequestHeaderFieldsTooLarge: 431,
				UnavailableForLegalReasons: 451,
				InternalServerError: 500,
				NotImplemented: 501,
				BadGateway: 502,
				ServiceUnavailable: 503,
				GatewayTimeout: 504,
				HttpVersionNotSupported: 505,
				VariantAlsoNegotiates: 506,
				InsufficientStorage: 507,
				LoopDetected: 508,
				NotExtended: 510,
				NetworkAuthenticationRequired: 511
			};
			Object.entries(Be).forEach(function(e) {
				var t = o(e, 2),
					n = t[0],
					r = t[1];
				Be[r] = n
			});
			var Le = Be;
			var De = function e(t) {
				var n = new _e(t),
					r = a(_e.prototype.request, n);
				return q.extend(r, _e.prototype, n, {
					allOwnKeys: !0
				}), q.extend(r, n, null, {
					allOwnKeys: !0
				}), r.create = function(n) {
					return e(je(t, n))
				}, r
			}(se);
			return De.Axios = _e, De.CanceledError = ve, De.CancelToken = Fe, De.isCancel = ye, De.VERSION =
				Ne, De.toFormData = G, De.AxiosError = M, De.Cancel = De.CanceledError, De.all = function(
				e) {
					return Promise.all(e)
				}, De.spread = function(e) {
					return function(t) {
						return e.apply(null, t)
					}
				}, De.isAxiosError = function(e) {
					return q.isObject(e) && !0 === e.isAxiosError
				}, De.mergeConfig = je, De.AxiosHeaders = he, De.formToJSON = function(e) {
					return oe(q.isHTMLForm(e) ? new FormData(e) : e)
				}, De.HttpStatusCode = Le, De.default = De, De
		});
		return {
			requestAction: function(me, action, config) {
				config.url = me.getActionUrl();
				config.method = "post";
				config.params = config.params || {};
				config.params = Object.assign(config.params, me.getOpt("serverparam"));
				config.params.action = action;
				return this.request(me, config)
			},
			request: function(me, config) {
				config.headers = config.headers || {};
				var customHeaders = me.getOpt("serverHeaders");
				if (customHeaders) {
					for (var key in customHeaders) {
						config.headers[key] = customHeaders[key]
					}
				}
				return axios(config)
			}
		}
	}();
	UE.image = function() {
		var imageCompression = null;
		! function(e, t) {
			imageCompression = t()
		}(this, function() {
			"use strict";

			function _mergeNamespaces(e, t) {
				return t.forEach(function(t) {
					t && "string" != typeof t && !Array.isArray(t) && Object.keys(t).forEach(
						function(r) {
							if ("default" !== r && !(r in e)) {
								var i = Object.getOwnPropertyDescriptor(t, r);
								Object.defineProperty(e, r, i.get ? i : {
									enumerable: !0,
									get: function() {
										return t[r]
									}
								})
							}
						})
				}), Object.freeze(e)
			}

			function copyExifWithoutOrientation(e, t) {
				return new Promise(function(r, i) {
					let o;
					return getApp1Segment(e).then(function(e) {
						try {
							return o = e, r(new Blob([t.slice(0, 2), o, t.slice(2)], {
								type: "image/jpeg"
							}))
						} catch (e) {
							return i(e)
						}
					}, i)
				})
			}
			const getApp1Segment = e => new Promise((t, r) => {
				const i = new FileReader;
				i.addEventListener("load", ({
					target: {
						result: e
					}
				}) => {
					const i = new DataView(e);
					let o = 0;
					if (65496 !== i.getUint16(o)) return r("not a valid JPEG");
					for (o += 2;;) {
						const a = i.getUint16(o);
						if (65498 === a) break;
						const s = i.getUint16(o + 2);
						if (65505 === a && 1165519206 === i.getUint32(o + 4)) {
							const a = o + 10;
							let f;
							switch (i.getUint16(a)) {
								case 18761:
									f = !0;
									break;
								case 19789:
									f = !1;
									break;
								default:
									return r("TIFF header contains invalid endian")
							}
							if (42 !== i.getUint16(a + 2, f)) return r(
								"TIFF header contains invalid version");
							const l = i.getUint32(a + 4, f),
								c = a + l + 2 + 12 * i.getUint16(a + l, f);
							for (let e = a + l + 2; e < c; e += 12) {
								if (274 == i.getUint16(e, f)) {
									if (3 !== i.getUint16(e + 2, f)) return r(
										"Orientation data type is invalid");
									if (1 !== i.getUint32(e + 4, f)) return r(
										"Orientation data count is invalid");
									i.setUint16(e + 8, 1, f);
									break
								}
							}
							return t(e.slice(o, o + 2 + s))
						}
						o += 2 + s
					}
					return t(new Blob)
				}), i.readAsArrayBuffer(e)
			});
			var e = {};
			! function(e) {
				var t, r, UZIP = {};
				e.exports = UZIP, UZIP.parse = function(e, t) {
						for (var r = UZIP.bin.readUshort, i = UZIP.bin.readUint, o = 0, a = {}, s =
								new Uint8Array(e), f = s.length - 4; 101010256 != i(s, f);) f--;
						o = f;
						o += 4;
						var l = r(s, o += 4);
						r(s, o += 2);
						var c = i(s, o += 2),
							u = i(s, o += 4);
						o += 4, o = u;
						for (var h = 0; h < l; h++) {
							i(s, o), o += 4, o += 4, o += 4, i(s, o += 4);
							c = i(s, o += 4);
							var d = i(s, o += 4),
								A = r(s, o += 4),
								g = r(s, o + 2),
								p = r(s, o + 4);
							o += 6;
							var m = i(s, o += 8);
							o += 4, o += A + g + p, UZIP._readLocal(s, m, a, c, d, t)
						}
						return a
					}, UZIP._readLocal = function(e, t, r, i, o, a) {
						var s = UZIP.bin.readUshort,
							f = UZIP.bin.readUint;
						f(e, t), s(e, t += 4), s(e, t += 2);
						var l = s(e, t += 2);
						f(e, t += 2), f(e, t += 4), t += 4;
						var c = s(e, t += 8),
							u = s(e, t += 2);
						t += 2;
						var h = UZIP.bin.readUTF8(e, t, c);
						if (t += c, t += u, a) r[h] = {
							size: o,
							csize: i
						};
						else {
							var d = new Uint8Array(e.buffer, t);
							if (0 == l) r[h] = new Uint8Array(d.buffer.slice(t, t + i));
							else {
								if (8 != l) throw "unknown compression method: " + l;
								var A = new Uint8Array(o);
								UZIP.inflateRaw(d, A), r[h] = A
							}
						}
					}, UZIP.inflateRaw = function(e, t) {
						return UZIP.F.inflate(e, t)
					}, UZIP.inflate = function(e, t) {
						return e[0], e[1], UZIP.inflateRaw(new Uint8Array(e.buffer, e.byteOffset + 2, e
							.length - 6), t)
					}, UZIP.deflate = function(e, t) {
						null == t && (t = {
							level: 6
						});
						var r = 0,
							i = new Uint8Array(50 + Math.floor(1.1 * e.length));
						i[r] = 120, i[r + 1] = 156, r += 2, r = UZIP.F.deflateRaw(e, i, r, t.level);
						var o = UZIP.adler(e, 0, e.length);
						return i[r + 0] = o >>> 24 & 255, i[r + 1] = o >>> 16 & 255, i[r + 2] = o >>> 8 &
							255, i[r + 3] = o >>> 0 & 255, new Uint8Array(i.buffer, 0, r + 4)
					}, UZIP.deflateRaw = function(e, t) {
						null == t && (t = {
							level: 6
						});
						var r = new Uint8Array(50 + Math.floor(1.1 * e.length)),
							i = UZIP.F.deflateRaw(e, r, i, t.level);
						return new Uint8Array(r.buffer, 0, i)
					}, UZIP.encode = function(e, t) {
						null == t && (t = !1);
						var r = 0,
							i = UZIP.bin.writeUint,
							o = UZIP.bin.writeUshort,
							a = {};
						for (var s in e) {
							var f = !UZIP._noNeed(s) && !t,
								l = e[s],
								c = UZIP.crc.crc(l, 0, l.length);
							a[s] = {
								cpr: f,
								usize: l.length,
								crc: c,
								file: f ? UZIP.deflateRaw(l) : l
							}
						}
						for (var s in a) r += a[s].file.length + 30 + 46 + 2 * UZIP.bin.sizeUTF8(s);
						r += 22;
						var u = new Uint8Array(r),
							h = 0,
							d = [];
						for (var s in a) {
							var A = a[s];
							d.push(h), h = UZIP._writeHeader(u, h, s, A, 0)
						}
						var g = 0,
							p = h;
						for (var s in a) {
							A = a[s];
							d.push(h), h = UZIP._writeHeader(u, h, s, A, 1, d[g++])
						}
						var m = h - p;
						return i(u, h, 101010256), h += 4, o(u, h += 4, g), o(u, h += 2, g), i(u, h += 2,
							m), i(u, h += 4, p), h += 4, h += 2, u.buffer
					}, UZIP._noNeed = function(e) {
						var t = e.split(".").pop().toLowerCase();
						return -1 != "png,jpg,jpeg,zip".indexOf(t)
					}, UZIP._writeHeader = function(e, t, r, i, o, a) {
						var s = UZIP.bin.writeUint,
							f = UZIP.bin.writeUshort,
							l = i.file;
						return s(e, t, 0 == o ? 67324752 : 33639248), t += 4, 1 == o && (t += 2), f(e, t,
							20), f(e, t += 2, 0), f(e, t += 2, i.cpr ? 8 : 0), s(e, t += 2, 0), s(e,
							t += 4, i.crc), s(e, t += 4, l.length), s(e, t += 4, i.usize), f(e, t += 4,
							UZIP.bin.sizeUTF8(r)), f(e, t += 2, 0), t += 2, 1 == o && (t += 2, t += 2,
							s(e, t += 6, a), t += 4), t += UZIP.bin.writeUTF8(e, t, r), 0 == o && (e
							.set(l, t), t += l.length), t
					}, UZIP.crc = {
						table: function() {
							for (var e = new Uint32Array(256), t = 0; t < 256; t++) {
								for (var r = t, i = 0; i < 8; i++) 1 & r ? r = 3988292384 ^ r >>> 1 :
									r >>>= 1;
								e[t] = r
							}
							return e
						}(),
						update: function(e, t, r, i) {
							for (var o = 0; o < i; o++) e = UZIP.crc.table[255 & (e ^ t[r + o])] ^ e >>>
								8;
							return e
						},
						crc: function(e, t, r) {
							return 4294967295 ^ UZIP.crc.update(4294967295, e, t, r)
						}
					}, UZIP.adler = function(e, t, r) {
						for (var i = 1, o = 0, a = t, s = t + r; a < s;) {
							for (var f = Math.min(a + 5552, s); a < f;) o += i += e[a++];
							i %= 65521, o %= 65521
						}
						return o << 16 | i
					}, UZIP.bin = {
						readUshort: function(e, t) {
							return e[t] | e[t + 1] << 8
						},
						writeUshort: function(e, t, r) {
							e[t] = 255 & r, e[t + 1] = r >> 8 & 255
						},
						readUint: function(e, t) {
							return 16777216 * e[t + 3] + (e[t + 2] << 16 | e[t + 1] << 8 | e[t])
						},
						writeUint: function(e, t, r) {
							e[t] = 255 & r, e[t + 1] = r >> 8 & 255, e[t + 2] = r >> 16 & 255, e[t +
								3] = r >> 24 & 255
						},
						readASCII: function(e, t, r) {
							for (var i = "", o = 0; o < r; o++) i += String.fromCharCode(e[t + o]);
							return i
						},
						writeASCII: function(e, t, r) {
							for (var i = 0; i < r.length; i++) e[t + i] = r.charCodeAt(i)
						},
						pad: function(e) {
							return e.length < 2 ? "0" + e : e
						},
						readUTF8: function(e, t, r) {
							for (var i, o = "", a = 0; a < r; a++) o += "%" + UZIP.bin.pad(e[t + a]
								.toString(16));
							try {
								i = decodeURIComponent(o)
							} catch (i) {
								return UZIP.bin.readASCII(e, t, r)
							}
							return i
						},
						writeUTF8: function(e, t, r) {
							for (var i = r.length, o = 0, a = 0; a < i; a++) {
								var s = r.charCodeAt(a);
								if (0 == (4294967168 & s)) e[t + o] = s, o++;
								else if (0 == (4294965248 & s)) e[t + o] = 192 | s >> 6, e[t + o + 1] =
									128 | s >> 0 & 63, o += 2;
								else if (0 == (4294901760 & s)) e[t + o] = 224 | s >> 12, e[t + o + 1] =
									128 | s >> 6 & 63, e[t + o + 2] = 128 | s >> 0 & 63, o += 3;
								else {
									if (0 != (4292870144 & s)) throw "e";
									e[t + o] = 240 | s >> 18, e[t + o + 1] = 128 | s >> 12 & 63, e[t +
											o + 2] = 128 | s >> 6 & 63, e[t + o + 3] = 128 | s >> 0 &
										63, o += 4
								}
							}
							return o
						},
						sizeUTF8: function(e) {
							for (var t = e.length, r = 0, i = 0; i < t; i++) {
								var o = e.charCodeAt(i);
								if (0 == (4294967168 & o)) r++;
								else if (0 == (4294965248 & o)) r += 2;
								else if (0 == (4294901760 & o)) r += 3;
								else {
									if (0 != (4292870144 & o)) throw "e";
									r += 4
								}
							}
							return r
						}
					}, UZIP.F = {}, UZIP.F.deflateRaw = function(e, t, r, i) {
						var o = [
								[0, 0, 0, 0, 0],
								[4, 4, 8, 4, 0],
								[4, 5, 16, 8, 0],
								[4, 6, 16, 16, 0],
								[4, 10, 16, 32, 0],
								[8, 16, 32, 32, 0],
								[8, 16, 128, 128, 0],
								[8, 32, 128, 256, 0],
								[32, 128, 258, 1024, 1],
								[32, 258, 258, 4096, 1]
							][i],
							a = UZIP.F.U,
							s = UZIP.F._goodIndex;
						UZIP.F._hash;
						var f = UZIP.F._putsE,
							l = 0,
							c = r << 3,
							u = 0,
							h = e.length;
						if (0 == i) {
							for (; l < h;) {
								f(t, c, l + (_ = Math.min(65535, h - l)) == h ? 1 : 0), c = UZIP.F
									._copyExact(e, l, _, t, c + 8), l += _
							}
							return c >>> 3
						}
						var d = a.lits,
							A = a.strt,
							g = a.prev,
							p = 0,
							m = 0,
							w = 0,
							v = 0,
							b = 0,
							y = 0;
						for (h > 2 && (A[y = UZIP.F._hash(e, 0)] = 0), l = 0; l < h; l++) {
							if (b = y, l + 1 < h - 2) {
								y = UZIP.F._hash(e, l + 1);
								var E = l + 1 & 32767;
								g[E] = A[y], A[y] = E
							}
							if (u <= l) {
								(p > 14e3 || m > 26697) && h - l > 100 && (u < l && (d[p] = l - u, p += 2,
									u = l), c = UZIP.F._writeBlock(l == h - 1 || u == h ? 1 : 0, d,
									p, v, e, w, l - w, t, c), p = m = v = 0, w = l);
								var F = 0;
								l < h - 2 && (F = UZIP.F._bestMatch(e, l, g, b, Math.min(o[2], h - l), o[
									3]));
								var _ = F >>> 16,
									B = 65535 & F;
								if (0 != F) {
									B = 65535 & F;
									var U = s(_ = F >>> 16, a.of0);
									a.lhst[257 + U]++;
									var C = s(B, a.df0);
									a.dhst[C]++, v += a.exb[U] + a.dxb[C], d[p] = _ << 23 | l - u, d[p +
										1] = B << 16 | U << 8 | C, p += 2, u = l + _
								} else a.lhst[e[l]]++;
								m++
							}
						}
						for (w == l && 0 != e.length || (u < l && (d[p] = l - u, p += 2, u = l), c = UZIP.F
								._writeBlock(1, d, p, v, e, w, l - w, t, c), p = 0, m = 0, p = m = v = 0,
								w = l); 0 != (7 & c);) c++;
						return c >>> 3
					}, UZIP.F._bestMatch = function(e, t, r, i, o, a) {
						var s = 32767 & t,
							f = r[s],
							l = s - f + 32768 & 32767;
						if (f == s || i != UZIP.F._hash(e, t - l)) return 0;
						for (var c = 0, u = 0, h = Math.min(32767, t); l <= h && 0 != --a && f != s;) {
							if (0 == c || e[t + c] == e[t + c - l]) {
								var d = UZIP.F._howLong(e, t, l);
								if (d > c) {
									if (u = l, (c = d) >= o) break;
									l + 2 < d && (d = l + 2);
									for (var A = 0, g = 0; g < d - 2; g++) {
										var p = t - l + g + 32768 & 32767,
											m = p - r[p] + 32768 & 32767;
										m > A && (A = m, f = p)
									}
								}
							}
							l += (s = f) - (f = r[s]) + 32768 & 32767
						}
						return c << 16 | u
					}, UZIP.F._howLong = function(e, t, r) {
						if (e[t] != e[t - r] || e[t + 1] != e[t + 1 - r] || e[t + 2] != e[t + 2 - r])
						return 0;
						var i = t,
							o = Math.min(e.length, t + 258);
						for (t += 3; t < o && e[t] == e[t - r];) t++;
						return t - i
					}, UZIP.F._hash = function(e, t) {
						return (e[t] << 8 | e[t + 1]) + (e[t + 2] << 4) & 65535
					}, UZIP.saved = 0, UZIP.F._writeBlock = function(e, t, r, i, o, a, s, f, l) {
						var c, u, h, d, A, g, p, m, w, v = UZIP.F.U,
							b = UZIP.F._putsF,
							y = UZIP.F._putsE;
						v.lhst[256]++, u = (c = UZIP.F.getTrees())[0], h = c[1], d = c[2], A = c[3], g = c[
							4], p = c[5], m = c[6], w = c[7];
						var E = 32 + (0 == (l + 3 & 7) ? 0 : 8 - (l + 3 & 7)) + (s << 3),
							F = i + UZIP.F.contSize(v.fltree, v.lhst) + UZIP.F.contSize(v.fdtree, v.dhst),
							_ = i + UZIP.F.contSize(v.ltree, v.lhst) + UZIP.F.contSize(v.dtree, v.dhst);
						_ += 14 + 3 * p + UZIP.F.contSize(v.itree, v.ihst) + (2 * v.ihst[16] + 3 * v.ihst[
							17] + 7 * v.ihst[18]);
						for (var B = 0; B < 286; B++) v.lhst[B] = 0;
						for (B = 0; B < 30; B++) v.dhst[B] = 0;
						for (B = 0; B < 19; B++) v.ihst[B] = 0;
						var U = E < F && E < _ ? 0 : F < _ ? 1 : 2;
						if (b(f, l, e), b(f, l + 1, U), l += 3, 0 == U) {
							for (; 0 != (7 & l);) l++;
							l = UZIP.F._copyExact(o, a, s, f, l)
						} else {
							var C, I;
							if (1 == U && (C = v.fltree, I = v.fdtree), 2 == U) {
								UZIP.F.makeCodes(v.ltree, u), UZIP.F.revCodes(v.ltree, u), UZIP.F.makeCodes(
									v.dtree, h), UZIP.F.revCodes(v.dtree, h), UZIP.F.makeCodes(v.itree,
									d), UZIP.F.revCodes(v.itree, d), C = v.ltree, I = v.dtree, y(f, l,
									A - 257), y(f, l += 5, g - 1), y(f, l += 5, p - 4), l += 4;
								for (var Q = 0; Q < p; Q++) y(f, l + 3 * Q, v.itree[1 + (v.ordr[Q] << 1)]);
								l += 3 * p, l = UZIP.F._codeTiny(m, v.itree, f, l), l = UZIP.F._codeTiny(w,
									v.itree, f, l)
							}
							for (var M = a, x = 0; x < r; x += 2) {
								for (var T = t[x], S = T >>> 23, R = M + (8388607 & T); M < R;) l = UZIP.F
									._writeLit(o[M++], C, f, l);
								if (0 != S) {
									var O = t[x + 1],
										P = O >> 16,
										H = O >> 8 & 255,
										L = 255 & O;
									y(f, l = UZIP.F._writeLit(257 + H, C, f, l), S - v.of0[H]), l += v.exb[
											H], b(f, l = UZIP.F._writeLit(L, I, f, l), P - v.df0[L]), l += v
										.dxb[L], M += S
								}
							}
							l = UZIP.F._writeLit(256, C, f, l)
						}
						return l
					}, UZIP.F._copyExact = function(e, t, r, i, o) {
						var a = o >>> 3;
						return i[a] = r, i[a + 1] = r >>> 8, i[a + 2] = 255 - i[a], i[a + 3] = 255 - i[a +
							1], a += 4, i.set(new Uint8Array(e.buffer, t, r), a), o + (r + 4 << 3)
					}, UZIP.F.getTrees = function() {
						for (var e = UZIP.F.U, t = UZIP.F._hufTree(e.lhst, e.ltree, 15), r = UZIP.F
								._hufTree(e.dhst, e.dtree, 15), i = [], o = UZIP.F._lenCodes(e.ltree, i),
								a = [], s = UZIP.F._lenCodes(e.dtree, a), f = 0; f < i.length; f += 2) e
							.ihst[i[f]]++;
						for (f = 0; f < a.length; f += 2) e.ihst[a[f]]++;
						for (var l = UZIP.F._hufTree(e.ihst, e.itree, 7), c = 19; c > 4 && 0 == e.itree[1 +
								(e.ordr[c - 1] << 1)];) c--;
						return [t, r, l, o, s, c, i, a]
					}, UZIP.F.getSecond = function(e) {
						for (var t = [], r = 0; r < e.length; r += 2) t.push(e[r + 1]);
						return t
					}, UZIP.F.nonZero = function(e) {
						for (var t = "", r = 0; r < e.length; r += 2) 0 != e[r + 1] && (t += (r >> 1) +
						",");
						return t
					}, UZIP.F.contSize = function(e, t) {
						for (var r = 0, i = 0; i < t.length; i++) r += t[i] * e[1 + (i << 1)];
						return r
					}, UZIP.F._codeTiny = function(e, t, r, i) {
						for (var o = 0; o < e.length; o += 2) {
							var a = e[o],
								s = e[o + 1];
							i = UZIP.F._writeLit(a, t, r, i);
							var f = 16 == a ? 2 : 17 == a ? 3 : 7;
							a > 15 && (UZIP.F._putsE(r, i, s, f), i += f)
						}
						return i
					}, UZIP.F._lenCodes = function(e, t) {
						for (var r = e.length; 2 != r && 0 == e[r - 1];) r -= 2;
						for (var i = 0; i < r; i += 2) {
							var o = e[i + 1],
								a = i + 3 < r ? e[i + 3] : -1,
								s = i + 5 < r ? e[i + 5] : -1,
								f = 0 == i ? -1 : e[i - 1];
							if (0 == o && a == o && s == o) {
								for (var l = i + 5; l + 2 < r && e[l + 2] == o;) l += 2;
								(c = Math.min(l + 1 - i >>> 1, 138)) < 11 ? t.push(17, c - 3) : t.push(18,
									c - 11), i += 2 * c - 2
							} else if (o == f && a == o && s == o) {
								for (l = i + 5; l + 2 < r && e[l + 2] == o;) l += 2;
								var c = Math.min(l + 1 - i >>> 1, 6);
								t.push(16, c - 3), i += 2 * c - 2
							} else t.push(o, 0)
						}
						return r >>> 1
					}, UZIP.F._hufTree = function(e, t, r) {
						var i = [],
							o = e.length,
							a = t.length,
							s = 0;
						for (s = 0; s < a; s += 2) t[s] = 0, t[s + 1] = 0;
						for (s = 0; s < o; s++) 0 != e[s] && i.push({
							lit: s,
							f: e[s]
						});
						var f = i.length,
							l = i.slice(0);
						if (0 == f) return 0;
						if (1 == f) {
							var c = i[0].lit;
							l = 0 == c ? 1 : 0;
							return t[1 + (c << 1)] = 1, t[1 + (l << 1)] = 1, 1
						}
						i.sort(function(e, t) {
							return e.f - t.f
						});
						var u = i[0],
							h = i[1],
							d = 0,
							A = 1,
							g = 2;
						for (i[0] = {
								lit: -1,
								f: u.f + h.f,
								l: u,
								r: h,
								d: 0
							}; A != f - 1;) u = d != A && (g == f || i[d].f < i[g].f) ? i[d++] : i[g++], h =
							d != A && (g == f || i[d].f < i[g].f) ? i[d++] : i[g++], i[A++] = {
								lit: -1,
								f: u.f + h.f,
								l: u,
								r: h
							};
						var p = UZIP.F.setDepth(i[A - 1], 0);
						for (p > r && (UZIP.F.restrictDepth(l, r, p), p = r), s = 0; s < f; s++) t[1 + (l[s]
							.lit << 1)] = l[s].d;
						return p
					}, UZIP.F.setDepth = function(e, t) {
						return -1 != e.lit ? (e.d = t, t) : Math.max(UZIP.F.setDepth(e.l, t + 1), UZIP.F
							.setDepth(e.r, t + 1))
					}, UZIP.F.restrictDepth = function(e, t, r) {
						var i = 0,
							o = 1 << r - t,
							a = 0;
						for (e.sort(function(e, t) {
								return t.d == e.d ? e.f - t.f : t.d - e.d
							}), i = 0; i < e.length && e[i].d > t; i++) {
							var s = e[i].d;
							e[i].d = t, a += o - (1 << r - s)
						}
						for (a >>>= r - t; a > 0;) {
							(s = e[i].d) < t ? (e[i].d++, a -= 1 << t - s - 1) : i++
						}
						for (; i >= 0; i--) e[i].d == t && a < 0 && (e[i].d--, a++);
						0 != a && console.log("debt left")
					}, UZIP.F._goodIndex = function(e, t) {
						var r = 0;
						return t[16 | r] <= e && (r |= 16), t[8 | r] <= e && (r |= 8), t[4 | r] <= e && (
							r |= 4), t[2 | r] <= e && (r |= 2), t[1 | r] <= e && (r |= 1), r
					}, UZIP.F._writeLit = function(e, t, r, i) {
						return UZIP.F._putsF(r, i, t[e << 1]), i + t[1 + (e << 1)]
					}, UZIP.F.inflate = function(e, t) {
						var r = Uint8Array;
						if (3 == e[0] && 0 == e[1]) return t || new r(0);
						var i = UZIP.F,
							o = i._bitsF,
							a = i._bitsE,
							s = i._decodeTiny,
							f = i.makeCodes,
							l = i.codes2map,
							c = i._get17,
							u = i.U,
							h = null == t;
						h && (t = new r(e.length >>> 2 << 3));
						for (var d, A, g = 0, p = 0, m = 0, w = 0, v = 0, b = 0, y = 0, E = 0, F = 0; 0 ==
							g;)
							if (g = o(e, F, 1), p = o(e, F + 1, 2), F += 3, 0 != p) {
								if (h && (t = UZIP.F._check(t, E + (1 << 17))), 1 == p && (d = u.flmap, A =
										u.fdmap, b = 511, y = 31), 2 == p) {
									m = a(e, F, 5) + 257, w = a(e, F + 5, 5) + 1, v = a(e, F + 10, 4) + 4,
										F += 14;
									for (var _ = 0; _ < 38; _ += 2) u.itree[_] = 0, u.itree[_ + 1] = 0;
									var B = 1;
									for (_ = 0; _ < v; _++) {
										var U = a(e, F + 3 * _, 3);
										u.itree[1 + (u.ordr[_] << 1)] = U, U > B && (B = U)
									}
									F += 3 * v, f(u.itree, B), l(u.itree, B, u.imap), d = u.lmap, A = u
										.dmap, F = s(u.imap, (1 << B) - 1, m + w, e, F, u.ttree);
									var C = i._copyOut(u.ttree, 0, m, u.ltree);
									b = (1 << C) - 1;
									var I = i._copyOut(u.ttree, m, w, u.dtree);
									y = (1 << I) - 1, f(u.ltree, C), l(u.ltree, C, d), f(u.dtree, I), l(u
										.dtree, I, A)
								}
								for (;;) {
									var Q = d[c(e, F) & b];
									F += 15 & Q;
									var M = Q >>> 4;
									if (M >>> 8 == 0) t[E++] = M;
									else {
										if (256 == M) break;
										var x = E + M - 254;
										if (M > 264) {
											var T = u.ldef[M - 257];
											x = E + (T >>> 3) + a(e, F, 7 & T), F += 7 & T
										}
										var S = A[c(e, F) & y];
										F += 15 & S;
										var R = S >>> 4,
											O = u.ddef[R],
											P = (O >>> 4) + o(e, F, 15 & O);
										for (F += 15 & O, h && (t = UZIP.F._check(t, E + (1 << 17))); E <
											x;) t[E] = t[E++ - P], t[E] = t[E++ - P], t[E] = t[E++ - P], t[
											E] = t[E++ - P];
										E = x
									}
								}
							} else {
								0 != (7 & F) && (F += 8 - (7 & F));
								var H = 4 + (F >>> 3),
									L = e[H - 4] | e[H - 3] << 8;
								h && (t = UZIP.F._check(t, E + L)), t.set(new r(e.buffer, e.byteOffset + H,
									L), E), F = H + L << 3, E += L
							} return t.length == E ? t : t.slice(0, E)
					}, UZIP.F._check = function(e, t) {
						var r = e.length;
						if (t <= r) return e;
						var i = new Uint8Array(Math.max(r << 1, t));
						return i.set(e, 0), i
					}, UZIP.F._decodeTiny = function(e, t, r, i, o, a) {
						for (var s = UZIP.F._bitsE, f = UZIP.F._get17, l = 0; l < r;) {
							var c = e[f(i, o) & t];
							o += 15 & c;
							var u = c >>> 4;
							if (u <= 15) a[l] = u, l++;
							else {
								var h = 0,
									d = 0;
								16 == u ? (d = 3 + s(i, o, 2), o += 2, h = a[l - 1]) : 17 == u ? (d = 3 + s(
									i, o, 3), o += 3) : 18 == u && (d = 11 + s(i, o, 7), o += 7);
								for (var A = l + d; l < A;) a[l] = h, l++
							}
						}
						return o
					}, UZIP.F._copyOut = function(e, t, r, i) {
						for (var o = 0, a = 0, s = i.length >>> 1; a < r;) {
							var f = e[a + t];
							i[a << 1] = 0, i[1 + (a << 1)] = f, f > o && (o = f), a++
						}
						for (; a < s;) i[a << 1] = 0, i[1 + (a << 1)] = 0, a++;
						return o
					}, UZIP.F.makeCodes = function(e, t) {
						for (var r, i, o, a, s = UZIP.F.U, f = e.length, l = s.bl_count, c = 0; c <= t; c++)
							l[c] = 0;
						for (c = 1; c < f; c += 2) l[e[c]]++;
						var u = s.next_code;
						for (r = 0, l[0] = 0, i = 1; i <= t; i++) r = r + l[i - 1] << 1, u[i] = r;
						for (o = 0; o < f; o += 2) 0 != (a = e[o + 1]) && (e[o] = u[a], u[a]++)
					}, UZIP.F.codes2map = function(e, t, r) {
						for (var i = e.length, o = UZIP.F.U.rev15, a = 0; a < i; a += 2)
							if (0 != e[a + 1])
								for (var s = a >> 1, f = e[a + 1], l = s << 4 | f, c = t - f, u = e[a] << c,
										h = u + (1 << c); u != h;) {
									r[o[u] >>> 15 - t] = l, u++
								}
					}, UZIP.F.revCodes = function(e, t) {
						for (var r = UZIP.F.U.rev15, i = 15 - t, o = 0; o < e.length; o += 2) {
							var a = e[o] << t - e[o + 1];
							e[o] = r[a] >>> i
						}
					}, UZIP.F._putsE = function(e, t, r) {
						r <<= 7 & t;
						var i = t >>> 3;
						e[i] |= r, e[i + 1] |= r >>> 8
					}, UZIP.F._putsF = function(e, t, r) {
						r <<= 7 & t;
						var i = t >>> 3;
						e[i] |= r, e[i + 1] |= r >>> 8, e[i + 2] |= r >>> 16
					}, UZIP.F._bitsE = function(e, t, r) {
						return (e[t >>> 3] | e[1 + (t >>> 3)] << 8) >>> (7 & t) & (1 << r) - 1
					}, UZIP.F._bitsF = function(e, t, r) {
						return (e[t >>> 3] | e[1 + (t >>> 3)] << 8 | e[2 + (t >>> 3)] << 16) >>> (7 & t) & (
							1 << r) - 1
					}, UZIP.F._get17 = function(e, t) {
						return (e[t >>> 3] | e[1 + (t >>> 3)] << 8 | e[2 + (t >>> 3)] << 16) >>> (7 & t)
					}, UZIP.F._get25 = function(e, t) {
						return (e[t >>> 3] | e[1 + (t >>> 3)] << 8 | e[2 + (t >>> 3)] << 16 | e[3 + (t >>>
							3)] << 24) >>> (7 & t)
					}, UZIP.F.U = (t = Uint16Array, r = Uint32Array, {
						next_code: new t(16),
						bl_count: new t(16),
						ordr: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
						of0: [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
							67, 83, 99, 115, 131, 163, 195, 227, 258, 999, 999, 999
						],
						exb: [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
							5, 5, 5, 0, 0, 0, 0
						],
						ldef: new t(32),
						df0: [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
							769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577,
							65535, 65535
						],
						dxb: [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
							11, 11, 12, 12, 13, 13, 0, 0
						],
						ddef: new r(32),
						flmap: new t(512),
						fltree: [],
						fdmap: new t(32),
						fdtree: [],
						lmap: new t(32768),
						ltree: [],
						ttree: [],
						dmap: new t(32768),
						dtree: [],
						imap: new t(512),
						itree: [],
						rev15: new t(32768),
						lhst: new r(286),
						dhst: new r(30),
						ihst: new r(19),
						lits: new r(15e3),
						strt: new t(65536),
						prev: new t(32768)
					}),
					function() {
						for (var e = UZIP.F.U, t = 0; t < 32768; t++) {
							var r = t;
							r = (4278255360 & (r = (4042322160 & (r = (3435973836 & (r = (2863311530 &
									r) >>> 1 | (1431655765 & r) << 1)) >>> 2 | (858993459 &
									r) << 2)) >>> 4 | (252645135 & r) << 4)) >>> 8 | (16711935 & r) << 8, e
								.rev15[t] = (r >>> 16 | r << 16) >>> 17
						}

						function pushV(e, t, r) {
							for (; 0 != t--;) e.push(0, r)
						}
						for (t = 0; t < 32; t++) e.ldef[t] = e.of0[t] << 3 | e.exb[t], e.ddef[t] = e.df0[
							t] << 4 | e.dxb[t];
						pushV(e.fltree, 144, 8), pushV(e.fltree, 112, 9), pushV(e.fltree, 24, 7), pushV(e
								.fltree, 8, 8), UZIP.F.makeCodes(e.fltree, 9), UZIP.F.codes2map(e.fltree, 9,
								e.flmap), UZIP.F.revCodes(e.fltree, 9), pushV(e.fdtree, 32, 5), UZIP.F
							.makeCodes(e.fdtree, 5), UZIP.F.codes2map(e.fdtree, 5, e.fdmap), UZIP.F
							.revCodes(e.fdtree, 5), pushV(e.itree, 19, 0), pushV(e.ltree, 286, 0), pushV(e
								.dtree, 30, 0), pushV(e.ttree, 320, 0)
					}()
			}({
				get exports() {
					return e
				},
				set exports(t) {
					e = t
				}
			});
			var UZIP = _mergeNamespaces({
				__proto__: null,
				default: e
			}, [e]);
			const UPNG = function() {
				var e = {
					nextZero(e, t) {
						for (; 0 != e[t];) t++;
						return t
					},
					readUshort: (e, t) => e[t] << 8 | e[t + 1],
					writeUshort(e, t, r) {
						e[t] = r >> 8 & 255, e[t + 1] = 255 & r
					},
					readUint: (e, t) => 16777216 * e[t] + (e[t + 1] << 16 | e[t + 2] << 8 | e[t +
						3]),
					writeUint(e, t, r) {
						e[t] = r >> 24 & 255, e[t + 1] = r >> 16 & 255, e[t + 2] = r >> 8 & 255, e[
							t + 3] = 255 & r
					},
					readASCII(e, t, r) {
						let i = "";
						for (let o = 0; o < r; o++) i += String.fromCharCode(e[t + o]);
						return i
					},
					writeASCII(e, t, r) {
						for (let i = 0; i < r.length; i++) e[t + i] = r.charCodeAt(i)
					},
					readBytes(e, t, r) {
						const i = [];
						for (let o = 0; o < r; o++) i.push(e[t + o]);
						return i
					},
					pad: e => e.length < 2 ? `0${e}` : e,
					readUTF8(t, r, i) {
						let o, a = "";
						for (let o = 0; o < i; o++) a += `%${e.pad(t[r+o].toString(16))}`;
						try {
							o = decodeURIComponent(a)
						} catch (o) {
							return e.readASCII(t, r, i)
						}
						return o
					}
				};

				function decodeImage(t, r, i, o) {
					const a = r * i,
						s = _getBPP(o),
						f = Math.ceil(r * s / 8),
						l = new Uint8Array(4 * a),
						c = new Uint32Array(l.buffer),
						{
							ctype: u
						} = o,
						{
							depth: h
						} = o,
						d = e.readUshort;
					if (6 == u) {
						const e = a << 2;
						if (8 == h)
							for (var A = 0; A < e; A += 4) l[A] = t[A], l[A + 1] = t[A + 1], l[A + 2] =
								t[A + 2], l[A + 3] = t[A + 3];
						if (16 == h)
							for (A = 0; A < e; A++) l[A] = t[A << 1]
					} else if (2 == u) {
						const e = o.tabs.tRNS;
						if (null == e) {
							if (8 == h)
								for (A = 0; A < a; A++) {
									var g = 3 * A;
									c[A] = 255 << 24 | t[g + 2] << 16 | t[g + 1] << 8 | t[g]
								}
							if (16 == h)
								for (A = 0; A < a; A++) {
									g = 6 * A;
									c[A] = 255 << 24 | t[g + 4] << 16 | t[g + 2] << 8 | t[g]
								}
						} else {
							var p = e[0];
							const r = e[1],
								i = e[2];
							if (8 == h)
								for (A = 0; A < a; A++) {
									var m = A << 2;
									g = 3 * A;
									c[A] = 255 << 24 | t[g + 2] << 16 | t[g + 1] << 8 | t[g], t[g] ==
										p && t[g + 1] == r && t[g + 2] == i && (l[m + 3] = 0)
								}
							if (16 == h)
								for (A = 0; A < a; A++) {
									m = A << 2, g = 6 * A;
									c[A] = 255 << 24 | t[g + 4] << 16 | t[g + 2] << 8 | t[g], d(t, g) ==
										p && d(t, g + 2) == r && d(t, g + 4) == i && (l[m + 3] = 0)
								}
						}
					} else if (3 == u) {
						const e = o.tabs.PLTE,
							s = o.tabs.tRNS,
							c = s ? s.length : 0;
						if (1 == h)
							for (var w = 0; w < i; w++) {
								var v = w * f,
									b = w * r;
								for (A = 0; A < r; A++) {
									m = b + A << 2;
									var y = 3 * (E = t[v + (A >> 3)] >> 7 - ((7 & A) << 0) & 1);
									l[m] = e[y], l[m + 1] = e[y + 1], l[m + 2] = e[y + 2], l[m + 3] =
										E < c ? s[E] : 255
								}
							}
						if (2 == h)
							for (w = 0; w < i; w++)
								for (v = w * f, b = w * r, A = 0; A < r; A++) {
									m = b + A << 2, y = 3 * (E = t[v + (A >> 2)] >> 6 - ((3 & A) << 1) &
										3);
									l[m] = e[y], l[m + 1] = e[y + 1], l[m + 2] = e[y + 2], l[m + 3] =
										E < c ? s[E] : 255
								}
						if (4 == h)
							for (w = 0; w < i; w++)
								for (v = w * f, b = w * r, A = 0; A < r; A++) {
									m = b + A << 2, y = 3 * (E = t[v + (A >> 1)] >> 4 - ((1 & A) << 2) &
										15);
									l[m] = e[y], l[m + 1] = e[y + 1], l[m + 2] = e[y + 2], l[m + 3] =
										E < c ? s[E] : 255
								}
						if (8 == h)
							for (A = 0; A < a; A++) {
								var E;
								m = A << 2, y = 3 * (E = t[A]);
								l[m] = e[y], l[m + 1] = e[y + 1], l[m + 2] = e[y + 2], l[m + 3] = E <
									c ? s[E] : 255
							}
					} else if (4 == u) {
						if (8 == h)
							for (A = 0; A < a; A++) {
								m = A << 2;
								var F = t[_ = A << 1];
								l[m] = F, l[m + 1] = F, l[m + 2] = F, l[m + 3] = t[_ + 1]
							}
						if (16 == h)
							for (A = 0; A < a; A++) {
								var _;
								m = A << 2, F = t[_ = A << 2];
								l[m] = F, l[m + 1] = F, l[m + 2] = F, l[m + 3] = t[_ + 2]
							}
					} else if (0 == u)
						for (p = o.tabs.tRNS ? o.tabs.tRNS : -1, w = 0; w < i; w++) {
							const e = w * f,
								i = w * r;
							if (1 == h)
								for (var B = 0; B < r; B++) {
									var U = (F = 255 * (t[e + (B >>> 3)] >>> 7 - (7 & B) & 1)) == 255 *
										p ? 0 : 255;
									c[i + B] = U << 24 | F << 16 | F << 8 | F
								} else if (2 == h)
									for (B = 0; B < r; B++) {
										U = (F = 85 * (t[e + (B >>> 2)] >>> 6 - ((3 & B) << 1) & 3)) ==
											85 * p ? 0 : 255;
										c[i + B] = U << 24 | F << 16 | F << 8 | F
									} else if (4 == h)
										for (B = 0; B < r; B++) {
											U = (F = 17 * (t[e + (B >>> 1)] >>> 4 - ((1 & B) << 2) &
												15)) == 17 * p ? 0 : 255;
											c[i + B] = U << 24 | F << 16 | F << 8 | F
										} else if (8 == h)
											for (B = 0; B < r; B++) {
												U = (F = t[e + B]) == p ? 0 : 255;
												c[i + B] = U << 24 | F << 16 | F << 8 | F
											} else if (16 == h)
												for (B = 0; B < r; B++) {
													F = t[e + (B << 1)], U = d(t, e + (B << 1)) == p ?
														0 : 255;
													c[i + B] = U << 24 | F << 16 | F << 8 | F
												}
						}
					return l
				}

				function _decompress(e, r, i, o) {
					const a = _getBPP(e),
						s = Math.ceil(i * a / 8),
						f = new Uint8Array((s + 1 + e.interlace) * o);
					return r = e.tabs.CgBI ? t(r, f) : _inflate(r, f), 0 == e.interlace ? r =
						_filterZero(r, e, 0, i, o) : 1 == e.interlace && (r = function _readInterlace(e,
							t) {
							const r = t.width,
								i = t.height,
								o = _getBPP(t),
								a = o >> 3,
								s = Math.ceil(r * o / 8),
								f = new Uint8Array(i * s);
							let l = 0;
							const c = [0, 0, 4, 0, 2, 0, 1],
								u = [0, 4, 0, 2, 0, 1, 0],
								h = [8, 8, 8, 4, 4, 2, 2],
								d = [8, 8, 4, 4, 2, 2, 1];
							let A = 0;
							for (; A < 7;) {
								const p = h[A],
									m = d[A];
								let w = 0,
									v = 0,
									b = c[A];
								for (; b < i;) b += p, v++;
								let y = u[A];
								for (; y < r;) y += m, w++;
								const E = Math.ceil(w * o / 8);
								_filterZero(e, t, l, w, v);
								let F = 0,
									_ = c[A];
								for (; _ < i;) {
									let t = u[A],
										i = l + F * E << 3;
									for (; t < r;) {
										var g;
										if (1 == o) g = (g = e[i >> 3]) >> 7 - (7 & i) & 1, f[_ *
											s + (t >> 3)] |= g << 7 - ((7 & t) << 0);
										if (2 == o) g = (g = e[i >> 3]) >> 6 - (7 & i) & 3, f[_ *
											s + (t >> 2)] |= g << 6 - ((3 & t) << 1);
										if (4 == o) g = (g = e[i >> 3]) >> 4 - (7 & i) & 15, f[_ *
											s + (t >> 1)] |= g << 4 - ((1 & t) << 2);
										if (o >= 8) {
											const r = _ * s + t * a;
											for (let t = 0; t < a; t++) f[r + t] = e[(i >> 3) + t]
										}
										i += o, t += m
									}
									F++, _ += p
								}
								w * v != 0 && (l += v * (1 + E)), A += 1
							}
							return f
						}(r, e)), r
				}

				function _inflate(e, r) {
					return t(new Uint8Array(e.buffer, 2, e.length - 6), r)
				}
				var t = function() {
					const e = {
						H: {}
					};
					return e.H.N = function(t, r) {
							const i = Uint8Array;
							let o, a, s = 0,
								f = 0,
								l = 0,
								c = 0,
								u = 0,
								h = 0,
								d = 0,
								A = 0,
								g = 0;
							if (3 == t[0] && 0 == t[1]) return r || new i(0);
							const p = e.H,
								m = p.b,
								w = p.e,
								v = p.R,
								b = p.n,
								y = p.A,
								E = p.Z,
								F = p.m,
								_ = null == r;
							for (_ && (r = new i(t.length >>> 2 << 5)); 0 == s;)
								if (s = m(t, g, 1), f = m(t, g + 1, 2), g += 3, 0 != f) {
									if (_ && (r = e.H.W(r, A + (1 << 17))), 1 == f && (o = F.J, a =
											F.h, h = 511, d = 31), 2 == f) {
										l = w(t, g, 5) + 257, c = w(t, g + 5, 5) + 1, u = w(t, g +
											10, 4) + 4, g += 14;
										let e = 1;
										for (var B = 0; B < 38; B += 2) F.Q[B] = 0, F.Q[B + 1] = 0;
										for (B = 0; B < u; B++) {
											const r = w(t, g + 3 * B, 3);
											F.Q[1 + (F.X[B] << 1)] = r, r > e && (e = r)
										}
										g += 3 * u, b(F.Q, e), y(F.Q, e, F.u), o = F.w, a = F.d, g =
											v(F.u, (1 << e) - 1, l + c, t, g, F.v);
										const r = p.V(F.v, 0, l, F.C);
										h = (1 << r) - 1;
										const i = p.V(F.v, l, c, F.D);
										d = (1 << i) - 1, b(F.C, r), y(F.C, r, o), b(F.D, i), y(F.D,
											i, a)
									}
									for (;;) {
										const e = o[E(t, g) & h];
										g += 15 & e;
										const i = e >>> 4;
										if (i >>> 8 == 0) r[A++] = i;
										else {
											if (256 == i) break; {
												let e = A + i - 254;
												if (i > 264) {
													const r = F.q[i - 257];
													e = A + (r >>> 3) + w(t, g, 7 & r), g += 7 & r
												}
												const o = a[E(t, g) & d];
												g += 15 & o;
												const s = o >>> 4,
													f = F.c[s],
													l = (f >>> 4) + m(t, g, 15 & f);
												for (g += 15 & f; A < e;) r[A] = r[A++ - l], r[A] =
													r[A++ - l], r[A] = r[A++ - l], r[A] = r[A++ -
													l];
												A = e
											}
										}
									}
								} else {
									0 != (7 & g) && (g += 8 - (7 & g));
									const o = 4 + (g >>> 3),
										a = t[o - 4] | t[o - 3] << 8;
									_ && (r = e.H.W(r, A + a)), r.set(new i(t.buffer, t.byteOffset +
										o, a), A), g = o + a << 3, A += a
								} return r.length == A ? r : r.slice(0, A)
						}, e.H.W = function(e, t) {
							const r = e.length;
							if (t <= r) return e;
							const i = new Uint8Array(r << 1);
							return i.set(e, 0), i
						}, e.H.R = function(t, r, i, o, a, s) {
							const f = e.H.e,
								l = e.H.Z;
							let c = 0;
							for (; c < i;) {
								const e = t[l(o, a) & r];
								a += 15 & e;
								const i = e >>> 4;
								if (i <= 15) s[c] = i, c++;
								else {
									let e = 0,
										t = 0;
									16 == i ? (t = 3 + f(o, a, 2), a += 2, e = s[c - 1]) : 17 == i ?
										(t = 3 + f(o, a, 3), a += 3) : 18 == i && (t = 11 + f(o, a,
											7), a += 7);
									const r = c + t;
									for (; c < r;) s[c] = e, c++
								}
							}
							return a
						}, e.H.V = function(e, t, r, i) {
							let o = 0,
								a = 0;
							const s = i.length >>> 1;
							for (; a < r;) {
								const r = e[a + t];
								i[a << 1] = 0, i[1 + (a << 1)] = r, r > o && (o = r), a++
							}
							for (; a < s;) i[a << 1] = 0, i[1 + (a << 1)] = 0, a++;
							return o
						}, e.H.n = function(t, r) {
							const i = e.H.m,
								o = t.length;
							let a, s, f;
							let l;
							const c = i.j;
							for (var u = 0; u <= r; u++) c[u] = 0;
							for (u = 1; u < o; u += 2) c[t[u]]++;
							const h = i.K;
							for (a = 0, c[0] = 0, s = 1; s <= r; s++) a = a + c[s - 1] << 1, h[s] =
								a;
							for (f = 0; f < o; f += 2) l = t[f + 1], 0 != l && (t[f] = h[l], h[l]++)
						}, e.H.A = function(t, r, i) {
							const o = t.length,
								a = e.H.m.r;
							for (let e = 0; e < o; e += 2)
								if (0 != t[e + 1]) {
									const o = e >> 1,
										s = t[e + 1],
										f = o << 4 | s,
										l = r - s;
									let c = t[e] << l;
									const u = c + (1 << l);
									for (; c != u;) {
										i[a[c] >>> 15 - r] = f, c++
									}
								}
						}, e.H.l = function(t, r) {
							const i = e.H.m.r,
								o = 15 - r;
							for (let e = 0; e < t.length; e += 2) {
								const a = t[e] << r - t[e + 1];
								t[e] = i[a] >>> o
							}
						}, e.H.M = function(e, t, r) {
							r <<= 7 & t;
							const i = t >>> 3;
							e[i] |= r, e[i + 1] |= r >>> 8
						}, e.H.I = function(e, t, r) {
							r <<= 7 & t;
							const i = t >>> 3;
							e[i] |= r, e[i + 1] |= r >>> 8, e[i + 2] |= r >>> 16
						}, e.H.e = function(e, t, r) {
							return (e[t >>> 3] | e[1 + (t >>> 3)] << 8) >>> (7 & t) & (1 << r) - 1
						}, e.H.b = function(e, t, r) {
							return (e[t >>> 3] | e[1 + (t >>> 3)] << 8 | e[2 + (t >>> 3)] << 16) >>>
								(7 & t) & (1 << r) - 1
						}, e.H.Z = function(e, t) {
							return (e[t >>> 3] | e[1 + (t >>> 3)] << 8 | e[2 + (t >>> 3)] << 16) >>>
								(7 & t)
						}, e.H.i = function(e, t) {
							return (e[t >>> 3] | e[1 + (t >>> 3)] << 8 | e[2 + (t >>> 3)] << 16 | e[
								3 + (t >>> 3)] << 24) >>> (7 & t)
						}, e.H.m = function() {
							const e = Uint16Array,
								t = Uint32Array;
							return {
								K: new e(16),
								j: new e(16),
								X: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1,
									15],
								S: [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43,
									51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 999, 999,
									999
								],
								T: [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4,
									4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0
								],
								q: new e(32),
								p: [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257,
									385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193,
									12289, 16385, 24577, 65535, 65535
								],
								z: [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9,
									9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0
								],
								c: new t(32),
								J: new e(512),
								_: [],
								h: new e(32),
								$: [],
								w: new e(32768),
								C: [],
								v: [],
								d: new e(32768),
								D: [],
								u: new e(512),
								Q: [],
								r: new e(32768),
								s: new t(286),
								Y: new t(30),
								a: new t(19),
								t: new t(15e3),
								k: new e(65536),
								g: new e(32768)
							}
						}(),
						function() {
							const t = e.H.m;
							for (var r = 0; r < 32768; r++) {
								let e = r;
								e = (2863311530 & e) >>> 1 | (1431655765 & e) << 1, e = (
									3435973836 & e) >>> 2 | (858993459 & e) << 2, e = (
									4042322160 & e) >>> 4 | (252645135 & e) << 4, e = (
									4278255360 & e) >>> 8 | (16711935 & e) << 8, t.r[r] = (e >>>
									16 | e << 16) >>> 17
							}

							function n(e, t, r) {
								for (; 0 != t--;) e.push(0, r)
							}
							for (r = 0; r < 32; r++) t.q[r] = t.S[r] << 3 | t.T[r], t.c[r] = t.p[
								r] << 4 | t.z[r];
							n(t._, 144, 8), n(t._, 112, 9), n(t._, 24, 7), n(t._, 8, 8), e.H.n(t._,
								9), e.H.A(t._, 9, t.J), e.H.l(t._, 9), n(t.$, 32, 5), e.H.n(t.$,
								5), e.H.A(t.$, 5, t.h), e.H.l(t.$, 5), n(t.Q, 19, 0), n(t.C,
								286, 0), n(t.D, 30, 0), n(t.v, 320, 0)
						}(), e.H.N
				}();

				function _getBPP(e) {
					return [1, null, 3, 1, 2, null, 4][e.ctype] * e.depth
				}

				function _filterZero(e, t, r, i, o) {
					let a = _getBPP(t);
					const s = Math.ceil(i * a / 8);
					let f, l;
					a = Math.ceil(a / 8);
					let c = e[r],
						u = 0;
					if (c > 1 && (e[r] = [0, 0, 1][c - 2]), 3 == c)
						for (u = a; u < s; u++) e[u + 1] = e[u + 1] + (e[u + 1 - a] >>> 1) & 255;
					for (let t = 0; t < o; t++)
						if (f = r + t * s, l = f + t + 1, c = e[l - 1], u = 0, 0 == c)
							for (; u < s; u++) e[f + u] = e[l + u];
						else if (1 == c) {
						for (; u < a; u++) e[f + u] = e[l + u];
						for (; u < s; u++) e[f + u] = e[l + u] + e[f + u - a]
					} else if (2 == c)
						for (; u < s; u++) e[f + u] = e[l + u] + e[f + u - s];
					else if (3 == c) {
						for (; u < a; u++) e[f + u] = e[l + u] + (e[f + u - s] >>> 1);
						for (; u < s; u++) e[f + u] = e[l + u] + (e[f + u - s] + e[f + u - a] >>> 1)
					} else {
						for (; u < a; u++) e[f + u] = e[l + u] + _paeth(0, e[f + u - s], 0);
						for (; u < s; u++) e[f + u] = e[l + u] + _paeth(e[f + u - a], e[f + u - s], e[
							f + u - a - s])
					}
					return e
				}

				function _paeth(e, t, r) {
					const i = e + t - r,
						o = i - e,
						a = i - t,
						s = i - r;
					return o * o <= a * a && o * o <= s * s ? e : a * a <= s * s ? t : r
				}

				function _IHDR(t, r, i) {
					i.width = e.readUint(t, r), r += 4, i.height = e.readUint(t, r), r += 4, i.depth =
						t[r], r++, i.ctype = t[r], r++, i.compress = t[r], r++, i.filter = t[r], r++, i
						.interlace = t[r], r++
				}

				function _copyTile(e, t, r, i, o, a, s, f, l) {
					const c = Math.min(t, o),
						u = Math.min(r, a);
					let h = 0,
						d = 0;
					for (let r = 0; r < u; r++)
						for (let a = 0; a < c; a++)
							if (s >= 0 && f >= 0 ? (h = r * t + a << 2, d = (f + r) * o + s + a << 2) :
								(h = (-f + r) * t - s + a << 2, d = r * o + a << 2), 0 == l) i[d] = e[
								h], i[d + 1] = e[h + 1], i[d + 2] = e[h + 2], i[d + 3] = e[h + 3];
							else if (1 == l) {
						var A = e[h + 3] * (1 / 255),
							g = e[h] * A,
							p = e[h + 1] * A,
							m = e[h + 2] * A,
							w = i[d + 3] * (1 / 255),
							v = i[d] * w,
							b = i[d + 1] * w,
							y = i[d + 2] * w;
						const t = 1 - A,
							r = A + w * t,
							o = 0 == r ? 0 : 1 / r;
						i[d + 3] = 255 * r, i[d + 0] = (g + v * t) * o, i[d + 1] = (p + b * t) * o, i[
							d + 2] = (m + y * t) * o
					} else if (2 == l) {
						A = e[h + 3], g = e[h], p = e[h + 1], m = e[h + 2], w = i[d + 3], v = i[d], b =
							i[d + 1], y = i[d + 2];
						A == w && g == v && p == b && m == y ? (i[d] = 0, i[d + 1] = 0, i[d + 2] = 0, i[
							d + 3] = 0) : (i[d] = g, i[d + 1] = p, i[d + 2] = m, i[d + 3] = A)
					} else if (3 == l) {
						A = e[h + 3], g = e[h], p = e[h + 1], m = e[h + 2], w = i[d + 3], v = i[d], b =
							i[d + 1], y = i[d + 2];
						if (A == w && g == v && p == b && m == y) continue;
						if (A < 220 && w > 20) return !1
					}
					return !0
				}
				return {
					decode: function decode(r) {
						const i = new Uint8Array(r);
						let o = 8;
						const a = e,
							s = a.readUshort,
							f = a.readUint,
							l = {
								tabs: {},
								frames: []
							},
							c = new Uint8Array(i.length);
						let u, h = 0,
							d = 0;
						const A = [137, 80, 78, 71, 13, 10, 26, 10];
						for (var g = 0; g < 8; g++)
							if (i[g] != A[g]) throw "The input is not a PNG file!";
						for (; o < i.length;) {
							const e = a.readUint(i, o);
							o += 4;
							const r = a.readASCII(i, o, 4);
							if (o += 4, "IHDR" == r) _IHDR(i, o, l);
							else if ("iCCP" == r) {
								for (var p = o; 0 != i[p];) p++;
								a.readASCII(i, o, p - o), i[p + 1];
								const s = i.slice(p + 2, o + e);
								let f = null;
								try {
									f = _inflate(s)
								} catch (e) {
									f = t(s)
								}
								l.tabs[r] = f
							} else if ("CgBI" == r) l.tabs[r] = i.slice(o, o + 4);
							else if ("IDAT" == r) {
								for (g = 0; g < e; g++) c[h + g] = i[o + g];
								h += e
							} else if ("acTL" == r) l.tabs[r] = {
								num_frames: f(i, o),
								num_plays: f(i, o + 4)
							}, u = new Uint8Array(i.length);
							else if ("fcTL" == r) {
								if (0 != d)(E = l.frames[l.frames.length - 1]).data = _decompress(l,
									u.slice(0, d), E.rect.width, E.rect.height), d = 0;
								const e = {
									x: f(i, o + 12),
									y: f(i, o + 16),
									width: f(i, o + 4),
									height: f(i, o + 8)
								};
								let t = s(i, o + 22);
								t = s(i, o + 20) / (0 == t ? 100 : t);
								const r = {
									rect: e,
									delay: Math.round(1e3 * t),
									dispose: i[o + 24],
									blend: i[o + 25]
								};
								l.frames.push(r)
							} else if ("fdAT" == r) {
								for (g = 0; g < e - 4; g++) u[d + g] = i[o + g + 4];
								d += e - 4
							} else if ("pHYs" == r) l.tabs[r] = [a.readUint(i, o), a.readUint(i, o +
								4), i[o + 8]];
							else if ("cHRM" == r) {
								l.tabs[r] = [];
								for (g = 0; g < 8; g++) l.tabs[r].push(a.readUint(i, o + 4 * g))
							} else if ("tEXt" == r || "zTXt" == r) {
								null == l.tabs[r] && (l.tabs[r] = {});
								var m = a.nextZero(i, o),
									w = a.readASCII(i, o, m - o),
									v = o + e - m - 1;
								if ("tEXt" == r) y = a.readASCII(i, m + 1, v);
								else {
									var b = _inflate(i.slice(m + 2, m + 2 + v));
									y = a.readUTF8(b, 0, b.length)
								}
								l.tabs[r][w] = y
							} else if ("iTXt" == r) {
								null == l.tabs[r] && (l.tabs[r] = {});
								m = 0, p = o;
								m = a.nextZero(i, p);
								w = a.readASCII(i, p, m - p);
								const t = i[p = m + 1];
								var y;
								i[p + 1], p += 2, m = a.nextZero(i, p), a.readASCII(i, p, m - p),
									p = m + 1, m = a.nextZero(i, p), a.readUTF8(i, p, m - p);
								v = e - ((p = m + 1) - o);
								if (0 == t) y = a.readUTF8(i, p, v);
								else {
									b = _inflate(i.slice(p, p + v));
									y = a.readUTF8(b, 0, b.length)
								}
								l.tabs[r][w] = y
							} else if ("PLTE" == r) l.tabs[r] = a.readBytes(i, o, e);
							else if ("hIST" == r) {
								const e = l.tabs.PLTE.length / 3;
								l.tabs[r] = [];
								for (g = 0; g < e; g++) l.tabs[r].push(s(i, o + 2 * g))
							} else if ("tRNS" == r) 3 == l.ctype ? l.tabs[r] = a.readBytes(i, o,
								e) : 0 == l.ctype ? l.tabs[r] = s(i, o) : 2 == l.ctype && (l.tabs[
									r] = [s(i, o), s(i, o + 2), s(i, o + 4)]);
							else if ("gAMA" == r) l.tabs[r] = a.readUint(i, o) / 1e5;
							else if ("sRGB" == r) l.tabs[r] = i[o];
							else if ("bKGD" == r) 0 == l.ctype || 4 == l.ctype ? l.tabs[r] = [s(i,
								o)] : 2 == l.ctype || 6 == l.ctype ? l.tabs[r] = [s(i, o), s(i,
								o + 2), s(i, o + 4)] : 3 == l.ctype && (l.tabs[r] = i[o]);
							else if ("IEND" == r) break;
							o += e, a.readUint(i, o), o += 4
						}
						var E;
						return 0 != d && ((E = l.frames[l.frames.length - 1]).data = _decompress(l,
								u.slice(0, d), E.rect.width, E.rect.height)), l.data = _decompress(
								l, c, l.width, l.height), delete l.compress, delete l.interlace,
							delete l.filter, l
					},
					toRGBA8: function toRGBA8(e) {
						const t = e.width,
							r = e.height;
						if (null == e.tabs.acTL) return [decodeImage(e.data, t, r, e).buffer];
						const i = [];
						null == e.frames[0].data && (e.frames[0].data = e.data);
						const o = t * r * 4,
							a = new Uint8Array(o),
							s = new Uint8Array(o),
							f = new Uint8Array(o);
						for (let c = 0; c < e.frames.length; c++) {
							const u = e.frames[c],
								h = u.rect.x,
								d = u.rect.y,
								A = u.rect.width,
								g = u.rect.height,
								p = decodeImage(u.data, A, g, e);
							if (0 != c)
								for (var l = 0; l < o; l++) f[l] = a[l];
							if (0 == u.blend ? _copyTile(p, A, g, a, t, r, h, d, 0) : 1 == u
								.blend && _copyTile(p, A, g, a, t, r, h, d, 1), i.push(a.buffer
									.slice(0)), 0 == u.dispose);
							else if (1 == u.dispose) _copyTile(s, A, g, a, t, r, h, d, 0);
							else if (2 == u.dispose)
								for (l = 0; l < o; l++) a[l] = f[l]
						}
						return i
					},
					_paeth: _paeth,
					_copyTile: _copyTile,
					_bin: e
				}
			}();
			! function() {
				const {
					_copyTile: e
				} = UPNG, {
					_bin: t
				} = UPNG, r = UPNG._paeth;
				var i = {
					table: function() {
						const e = new Uint32Array(256);
						for (let t = 0; t < 256; t++) {
							let r = t;
							for (let e = 0; e < 8; e++) 1 & r ? r = 3988292384 ^ r >>> 1 : r >>>= 1;
							e[t] = r
						}
						return e
					}(),
					update(e, t, r, o) {
						for (let a = 0; a < o; a++) e = i.table[255 & (e ^ t[r + a])] ^ e >>> 8;
						return e
					},
					crc: (e, t, r) => 4294967295 ^ i.update(4294967295, e, t, r)
				};

				function addErr(e, t, r, i) {
					t[r] += e[0] * i >> 4, t[r + 1] += e[1] * i >> 4, t[r + 2] += e[2] * i >> 4, t[r + 3] +=
						e[3] * i >> 4
				}

				function N(e) {
					return Math.max(0, Math.min(255, e))
				}

				function D(e, t) {
					const r = e[0] - t[0],
						i = e[1] - t[1],
						o = e[2] - t[2],
						a = e[3] - t[3];
					return r * r + i * i + o * o + a * a
				}

				function dither(e, t, r, i, o, a, s) {
					null == s && (s = 1);
					const f = i.length,
						l = [];
					for (var c = 0; c < f; c++) {
						const e = i[c];
						l.push([e >>> 0 & 255, e >>> 8 & 255, e >>> 16 & 255, e >>> 24 & 255])
					}
					for (c = 0; c < f; c++) {
						let e = 4294967295;
						for (var u = 0, h = 0; h < f; h++) {
							var d = D(l[c], l[h]);
							h != c && d < e && (e = d, u = h)
						}
					}
					const A = new Uint32Array(o.buffer),
						g = new Int16Array(t * r * 4),
						p = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5];
					for (c = 0; c < p.length; c++) p[c] = 255 * ((p[c] + .5) / 16 - .5);
					for (let o = 0; o < r; o++)
						for (let w = 0; w < t; w++) {
							var m;
							c = 4 * (o * t + w);
							if (2 != s) m = [N(e[c] + g[c]), N(e[c + 1] + g[c + 1]), N(e[c + 2] + g[c + 2]),
								N(e[c + 3] + g[c + 3])
							];
							else {
								d = p[4 * (3 & o) + (3 & w)];
								m = [N(e[c] + d), N(e[c + 1] + d), N(e[c + 2] + d), N(e[c + 3] + d)]
							}
							u = 0;
							let v = 16777215;
							for (h = 0; h < f; h++) {
								const e = D(m, l[h]);
								e < v && (v = e, u = h)
							}
							const b = l[u],
								y = [m[0] - b[0], m[1] - b[1], m[2] - b[2], m[3] - b[3]];
							1 == s && (w != t - 1 && addErr(y, g, c + 4, 7), o != r - 1 && (0 != w &&
								addErr(y, g, c + 4 * t - 4, 3), addErr(y, g, c + 4 * t, 5), w != t -
								1 && addErr(y, g, c + 4 * t + 4, 1))), a[c >> 2] = u, A[c >> 2] = i[u]
						}
				}

				function _main(e, r, o, a, s) {
					null == s && (s = {});
					const {
						crc: f
					} = i, l = t.writeUint, c = t.writeUshort, u = t.writeASCII;
					let h = 8;
					const d = e.frames.length > 1;
					let A, g = !1,
						p = 33 + (d ? 20 : 0);
					if (null != s.sRGB && (p += 13), null != s.pHYs && (p += 21), null != s.iCCP && (A =
							pako.deflate(s.iCCP), p += 21 + A.length + 4), 3 == e.ctype) {
						for (var m = e.plte.length, w = 0; w < m; w++) e.plte[w] >>> 24 != 255 && (g = !0);
						p += 8 + 3 * m + 4 + (g ? 8 + 1 * m + 4 : 0)
					}
					for (var v = 0; v < e.frames.length; v++) {
						d && (p += 38), p += (F = e.frames[v]).cimg.length + 12, 0 != v && (p += 4)
					}
					p += 12;
					const b = new Uint8Array(p),
						y = [137, 80, 78, 71, 13, 10, 26, 10];
					for (w = 0; w < 8; w++) b[w] = y[w];
					if (l(b, h, 13), h += 4, u(b, h, "IHDR"), h += 4, l(b, h, r), h += 4, l(b, h, o), h +=
						4, b[h] = e.depth, h++, b[h] = e.ctype, h++, b[h] = 0, h++, b[h] = 0, h++, b[h] = 0,
						h++, l(b, h, f(b, h - 17, 17)), h += 4, null != s.sRGB && (l(b, h, 1), h += 4, u(b,
							h, "sRGB"), h += 4, b[h] = s.sRGB, h++, l(b, h, f(b, h - 5, 5)), h += 4),
						null != s.iCCP) {
						const e = 13 + A.length;
						l(b, h, e), h += 4, u(b, h, "iCCP"), h += 4, u(b, h, "ICC profile"), h += 11, h +=
							2, b.set(A, h), h += A.length, l(b, h, f(b, h - (e + 4), e + 4)), h += 4
					}
					if (null != s.pHYs && (l(b, h, 9), h += 4, u(b, h, "pHYs"), h += 4, l(b, h, s.pHYs[0]),
							h += 4, l(b, h, s.pHYs[1]), h += 4, b[h] = s.pHYs[2], h++, l(b, h, f(b, h - 13,
								13)), h += 4), d && (l(b, h, 8), h += 4, u(b, h, "acTL"), h += 4, l(b, h, e
							.frames.length), h += 4, l(b, h, null != s.loop ? s.loop : 0), h += 4, l(b,
							h, f(b, h - 12, 12)), h += 4), 3 == e.ctype) {
						l(b, h, 3 * (m = e.plte.length)), h += 4, u(b, h, "PLTE"), h += 4;
						for (w = 0; w < m; w++) {
							const t = 3 * w,
								r = e.plte[w],
								i = 255 & r,
								o = r >>> 8 & 255,
								a = r >>> 16 & 255;
							b[h + t + 0] = i, b[h + t + 1] = o, b[h + t + 2] = a
						}
						if (h += 3 * m, l(b, h, f(b, h - 3 * m - 4, 3 * m + 4)), h += 4, g) {
							l(b, h, m), h += 4, u(b, h, "tRNS"), h += 4;
							for (w = 0; w < m; w++) b[h + w] = e.plte[w] >>> 24 & 255;
							h += m, l(b, h, f(b, h - m - 4, m + 4)), h += 4
						}
					}
					let E = 0;
					for (v = 0; v < e.frames.length; v++) {
						var F = e.frames[v];
						d && (l(b, h, 26), h += 4, u(b, h, "fcTL"), h += 4, l(b, h, E++), h += 4, l(b, h, F
								.rect.width), h += 4, l(b, h, F.rect.height), h += 4, l(b, h, F.rect.x),
							h += 4, l(b, h, F.rect.y), h += 4, c(b, h, a[v]), h += 2, c(b, h, 1e3), h +=
							2, b[h] = F.dispose, h++, b[h] = F.blend, h++, l(b, h, f(b, h - 30, 30)),
							h += 4);
						const t = F.cimg;
						l(b, h, (m = t.length) + (0 == v ? 0 : 4)), h += 4;
						const r = h;
						u(b, h, 0 == v ? "IDAT" : "fdAT"), h += 4, 0 != v && (l(b, h, E++), h += 4), b.set(
							t, h), h += m, l(b, h, f(b, r, h - r)), h += 4
					}
					return l(b, h, 0), h += 4, u(b, h, "IEND"), h += 4, l(b, h, f(b, h - 4, 4)), h += 4, b
						.buffer
				}

				function compressPNG(e, t, r) {
					for (let i = 0; i < e.frames.length; i++) {
						const o = e.frames[i];
						o.rect.width;
						const a = o.rect.height,
							s = new Uint8Array(a * o.bpl + a);
						o.cimg = _filterZero(o.img, a, o.bpp, o.bpl, s, t, r)
					}
				}

				function compress(t, r, i, o, a) {
					const s = a[0],
						f = a[1],
						l = a[2],
						c = a[3],
						u = a[4],
						h = a[5];
					let d = 6,
						A = 8,
						g = 255;
					for (var p = 0; p < t.length; p++) {
						const e = new Uint8Array(t[p]);
						for (var m = e.length, w = 0; w < m; w += 4) g &= e[w + 3]
					}
					const v = 255 != g,
						b = function framize(t, r, i, o, a, s) {
							const f = [];
							for (var l = 0; l < t.length; l++) {
								const h = new Uint8Array(t[l]),
									A = new Uint32Array(h.buffer);
								var c;
								let g = 0,
									p = 0,
									m = r,
									w = i,
									v = o ? 1 : 0;
								if (0 != l) {
									const b = s || o || 1 == l || 0 != f[l - 2].dispose ? 1 : 2;
									let y = 0,
										E = 1e9;
									for (let e = 0; e < b; e++) {
										var u = new Uint8Array(t[l - 1 - e]);
										const o = new Uint32Array(t[l - 1 - e]);
										let s = r,
											f = i,
											c = -1,
											h = -1;
										for (let e = 0; e < i; e++)
											for (let t = 0; t < r; t++) {
												A[d = e * r + t] != o[d] && (t < s && (s = t), t > c && (c =
													t), e < f && (f = e), e > h && (h = e))
											} - 1 == c && (s = f = c = h = 0), a && (1 == (1 & s) && s--,
												1 == (1 & f) && f--);
										const v = (c - s + 1) * (h - f + 1);
										v < E && (E = v, y = e, g = s, p = f, m = c - s + 1, w = h - f + 1)
									}
									u = new Uint8Array(t[l - 1 - y]);
									1 == y && (f[l - 1].dispose = 2), c = new Uint8Array(m * w * 4), e(u, r,
											i, c, m, w, -g, -p, 0), v = e(h, r, i, c, m, w, -g, -p, 3) ? 1 :
										0, 1 == v ? _prepareDiff(h, r, i, c, {
											x: g,
											y: p,
											width: m,
											height: w
										}) : e(h, r, i, c, m, w, -g, -p, 0)
								} else c = h.slice(0);
								f.push({
									rect: {
										x: g,
										y: p,
										width: m,
										height: w
									},
									img: c,
									blend: v,
									dispose: 0
								})
							}
							if (o)
								for (l = 0; l < f.length; l++) {
									if (1 == (A = f[l]).blend) continue;
									const e = A.rect,
										o = f[l - 1].rect,
										s = Math.min(e.x, o.x),
										c = Math.min(e.y, o.y),
										u = {
											x: s,
											y: c,
											width: Math.max(e.x + e.width, o.x + o.width) - s,
											height: Math.max(e.y + e.height, o.y + o.height) - c
										};
									f[l - 1].dispose = 1, l - 1 != 0 && _updateFrame(t, r, i, f, l - 1, u,
										a), _updateFrame(t, r, i, f, l, u, a)
								}
							let h = 0;
							if (1 != t.length)
								for (var d = 0; d < f.length; d++) {
									var A;
									h += (A = f[d]).rect.width * A.rect.height
								}
							return f
						}(t, r, i, s, f, l),
						y = {},
						E = [],
						F = [];
					if (0 != o) {
						const e = [];
						for (w = 0; w < b.length; w++) e.push(b[w].img.buffer);
						const t = function concatRGBA(e) {
								let t = 0;
								for (var r = 0; r < e.length; r++) t += e[r].byteLength;
								const i = new Uint8Array(t);
								let o = 0;
								for (r = 0; r < e.length; r++) {
									const t = new Uint8Array(e[r]),
										a = t.length;
									for (let e = 0; e < a; e += 4) {
										let r = t[e],
											a = t[e + 1],
											s = t[e + 2];
										const f = t[e + 3];
										0 == f && (r = a = s = 0), i[o + e] = r, i[o + e + 1] = a, i[o + e +
											2] = s, i[o + e + 3] = f
									}
									o += a
								}
								return i.buffer
							}(e),
							r = quantize(t, o);
						for (w = 0; w < r.plte.length; w++) E.push(r.plte[w].est.rgba);
						let i = 0;
						for (w = 0; w < b.length; w++) {
							const e = (B = b[w]).img.length;
							var _ = new Uint8Array(r.inds.buffer, i >> 2, e >> 2);
							F.push(_);
							const t = new Uint8Array(r.abuf, i, e);
							h && dither(B.img, B.rect.width, B.rect.height, E, t, _), B.img.set(t), i += e
						}
					} else
						for (p = 0; p < b.length; p++) {
							var B = b[p];
							const e = new Uint32Array(B.img.buffer);
							var U = B.rect.width;
							m = e.length, _ = new Uint8Array(m);
							F.push(_);
							for (w = 0; w < m; w++) {
								const t = e[w];
								if (0 != w && t == e[w - 1]) _[w] = _[w - 1];
								else if (w > U && t == e[w - U]) _[w] = _[w - U];
								else {
									let e = y[t];
									if (null == e && (y[t] = e = E.length, E.push(t), E.length >= 300))
										break;
									_[w] = e
								}
							}
						}
					const C = E.length;
					C <= 256 && 0 == u && (A = C <= 2 ? 1 : C <= 4 ? 2 : C <= 16 ? 4 : 8, A = Math.max(A,
						c));
					for (p = 0; p < b.length; p++) {
						(B = b[p]).rect.x, B.rect.y;
						U = B.rect.width;
						const e = B.rect.height;
						let t = B.img;
						new Uint32Array(t.buffer);
						let r = 4 * U,
							i = 4;
						if (C <= 256 && 0 == u) {
							r = Math.ceil(A * U / 8);
							var I = new Uint8Array(r * e);
							const o = F[p];
							for (let t = 0; t < e; t++) {
								w = t * r;
								const e = t * U;
								if (8 == A)
									for (var Q = 0; Q < U; Q++) I[w + Q] = o[e + Q];
								else if (4 == A)
									for (Q = 0; Q < U; Q++) I[w + (Q >> 1)] |= o[e + Q] << 4 - 4 * (1 & Q);
								else if (2 == A)
									for (Q = 0; Q < U; Q++) I[w + (Q >> 2)] |= o[e + Q] << 6 - 2 * (3 & Q);
								else if (1 == A)
									for (Q = 0; Q < U; Q++) I[w + (Q >> 3)] |= o[e + Q] << 7 - 1 * (7 & Q)
							}
							t = I, d = 3, i = 1
						} else if (0 == v && 1 == b.length) {
							I = new Uint8Array(U * e * 3);
							const o = U * e;
							for (w = 0; w < o; w++) {
								const e = 3 * w,
									r = 4 * w;
								I[e] = t[r], I[e + 1] = t[r + 1], I[e + 2] = t[r + 2]
							}
							t = I, d = 2, i = 3, r = 3 * U
						}
						B.img = t, B.bpl = r, B.bpp = i
					}
					return {
						ctype: d,
						depth: A,
						plte: E,
						frames: b
					}
				}

				function _updateFrame(t, r, i, o, a, s, f) {
					const l = Uint8Array,
						c = Uint32Array,
						u = new l(t[a - 1]),
						h = new c(t[a - 1]),
						d = a + 1 < t.length ? new l(t[a + 1]) : null,
						A = new l(t[a]),
						g = new c(A.buffer);
					let p = r,
						m = i,
						w = -1,
						v = -1;
					for (let e = 0; e < s.height; e++)
						for (let t = 0; t < s.width; t++) {
							const i = s.x + t,
								f = s.y + e,
								l = f * r + i,
								c = g[l];
							0 == c || 0 == o[a - 1].dispose && h[l] == c && (null == d || 0 != d[4 * l +
								3]) || (i < p && (p = i), i > w && (w = i), f < m && (m = f), f > v && (v =
									f))
						} - 1 == w && (p = m = w = v = 0), f && (1 == (1 & p) && p--, 1 == (1 & m) && m--),
						s = {
							x: p,
							y: m,
							width: w - p + 1,
							height: v - m + 1
						};
					const b = o[a];
					b.rect = s, b.blend = 1, b.img = new Uint8Array(s.width * s.height * 4), 0 == o[a - 1]
						.dispose ? (e(u, r, i, b.img, s.width, s.height, -s.x, -s.y, 0), _prepareDiff(A, r,
							i, b.img, s)) : e(A, r, i, b.img, s.width, s.height, -s.x, -s.y, 0)
				}

				function _prepareDiff(t, r, i, o, a) {
					e(t, r, i, o, a.width, a.height, -a.x, -a.y, 2)
				}

				function _filterZero(e, t, r, i, o, a, s) {
					const f = [];
					let l, c = [0, 1, 2, 3, 4]; - 1 != a ? c = [a] : (t * i > 5e5 || 1 == r) && (c = [0]),
						s && (l = {
							level: 0
						});
					const u = UZIP;
					for (var h = 0; h < c.length; h++) {
						for (let a = 0; a < t; a++) _filterLine(o, e, a, i, r, c[h]);
						f.push(u.deflate(o, l))
					}
					let d, A = 1e9;
					for (h = 0; h < f.length; h++) f[h].length < A && (d = h, A = f[h].length);
					return f[d]
				}

				function _filterLine(e, t, i, o, a, s) {
					const f = i * o;
					let l = f + i;
					if (e[l] = s, l++, 0 == s)
						if (o < 500)
							for (var c = 0; c < o; c++) e[l + c] = t[f + c];
						else e.set(new Uint8Array(t.buffer, f, o), l);
					else if (1 == s) {
						for (c = 0; c < a; c++) e[l + c] = t[f + c];
						for (c = a; c < o; c++) e[l + c] = t[f + c] - t[f + c - a] + 256 & 255
					} else if (0 == i) {
						for (c = 0; c < a; c++) e[l + c] = t[f + c];
						if (2 == s)
							for (c = a; c < o; c++) e[l + c] = t[f + c];
						if (3 == s)
							for (c = a; c < o; c++) e[l + c] = t[f + c] - (t[f + c - a] >> 1) + 256 & 255;
						if (4 == s)
							for (c = a; c < o; c++) e[l + c] = t[f + c] - r(t[f + c - a], 0, 0) + 256 & 255
					} else {
						if (2 == s)
							for (c = 0; c < o; c++) e[l + c] = t[f + c] + 256 - t[f + c - o] & 255;
						if (3 == s) {
							for (c = 0; c < a; c++) e[l + c] = t[f + c] + 256 - (t[f + c - o] >> 1) & 255;
							for (c = a; c < o; c++) e[l + c] = t[f + c] + 256 - (t[f + c - o] + t[f + c -
								a] >> 1) & 255
						}
						if (4 == s) {
							for (c = 0; c < a; c++) e[l + c] = t[f + c] + 256 - r(0, t[f + c - o], 0) & 255;
							for (c = a; c < o; c++) e[l + c] = t[f + c] + 256 - r(t[f + c - a], t[f + c -
								o], t[f + c - a - o]) & 255
						}
					}
				}

				function quantize(e, t) {
					const r = new Uint8Array(e),
						i = r.slice(0),
						o = new Uint32Array(i.buffer),
						a = getKDtree(i, t),
						s = a[0],
						f = a[1],
						l = r.length,
						c = new Uint8Array(l >> 2);
					let u;
					if (r.length < 2e7)
						for (var h = 0; h < l; h += 4) {
							u = getNearest(s, d = r[h] * (1 / 255), A = r[h + 1] * (1 / 255), g = r[h + 2] *
									(1 / 255), p = r[h + 3] * (1 / 255)), c[h >> 2] = u.ind, o[h >> 2] = u
								.est.rgba
						} else
							for (h = 0; h < l; h += 4) {
								var d = r[h] * (1 / 255),
									A = r[h + 1] * (1 / 255),
									g = r[h + 2] * (1 / 255),
									p = r[h + 3] * (1 / 255);
								for (u = s; u.left;) u = planeDst(u.est, d, A, g, p) <= 0 ? u.left : u
								.right;
								c[h >> 2] = u.ind, o[h >> 2] = u.est.rgba
							}
					return {
						abuf: i.buffer,
						inds: c,
						plte: f
					}
				}

				function getKDtree(e, t, r) {
					null == r && (r = 1e-4);
					const i = new Uint32Array(e.buffer),
						o = {
							i0: 0,
							i1: e.length,
							bst: null,
							est: null,
							tdst: 0,
							left: null,
							right: null
						};
					o.bst = stats(e, o.i0, o.i1), o.est = estats(o.bst);
					const a = [o];
					for (; a.length < t;) {
						let t = 0,
							o = 0;
						for (var s = 0; s < a.length; s++) a[s].est.L > t && (t = a[s].est.L, o = s);
						if (t < r) break;
						const f = a[o],
							l = splitPixels(e, i, f.i0, f.i1, f.est.e, f.est.eMq255);
						if (f.i0 >= l || f.i1 <= l) {
							f.est.L = 0;
							continue
						}
						const c = {
							i0: f.i0,
							i1: l,
							bst: null,
							est: null,
							tdst: 0,
							left: null,
							right: null
						};
						c.bst = stats(e, c.i0, c.i1), c.est = estats(c.bst);
						const u = {
							i0: l,
							i1: f.i1,
							bst: null,
							est: null,
							tdst: 0,
							left: null,
							right: null
						};
						u.bst = {
							R: [],
							m: [],
							N: f.bst.N - c.bst.N
						};
						for (s = 0; s < 16; s++) u.bst.R[s] = f.bst.R[s] - c.bst.R[s];
						for (s = 0; s < 4; s++) u.bst.m[s] = f.bst.m[s] - c.bst.m[s];
						u.est = estats(u.bst), f.left = c, f.right = u, a[o] = c, a.push(u)
					}
					a.sort((e, t) => t.bst.N - e.bst.N);
					for (s = 0; s < a.length; s++) a[s].ind = s;
					return [o, a]
				}

				function getNearest(e, t, r, i, o) {
					if (null == e.left) return e.tdst = function dist(e, t, r, i, o) {
						const a = t - e[0],
							s = r - e[1],
							f = i - e[2],
							l = o - e[3];
						return a * a + s * s + f * f + l * l
					}(e.est.q, t, r, i, o), e;
					const a = planeDst(e.est, t, r, i, o);
					let s = e.left,
						f = e.right;
					a > 0 && (s = e.right, f = e.left);
					const l = getNearest(s, t, r, i, o);
					if (l.tdst <= a * a) return l;
					const c = getNearest(f, t, r, i, o);
					return c.tdst < l.tdst ? c : l
				}

				function planeDst(e, t, r, i, o) {
					const {
						e: a
					} = e;
					return a[0] * t + a[1] * r + a[2] * i + a[3] * o - e.eMq
				}

				function splitPixels(e, t, r, i, o, a) {
					for (i -= 4; r < i;) {
						for (; vecDot(e, r, o) <= a;) r += 4;
						for (; vecDot(e, i, o) > a;) i -= 4;
						if (r >= i) break;
						const s = t[r >> 2];
						t[r >> 2] = t[i >> 2], t[i >> 2] = s, r += 4, i -= 4
					}
					for (; vecDot(e, r, o) > a;) r -= 4;
					return r + 4
				}

				function vecDot(e, t, r) {
					return e[t] * r[0] + e[t + 1] * r[1] + e[t + 2] * r[2] + e[t + 3] * r[3]
				}

				function stats(e, t, r) {
					const i = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						o = [0, 0, 0, 0],
						a = r - t >> 2;
					for (let a = t; a < r; a += 4) {
						const t = e[a] * (1 / 255),
							r = e[a + 1] * (1 / 255),
							s = e[a + 2] * (1 / 255),
							f = e[a + 3] * (1 / 255);
						o[0] += t, o[1] += r, o[2] += s, o[3] += f, i[0] += t * t, i[1] += t * r, i[2] +=
							t * s, i[3] += t * f, i[5] += r * r, i[6] += r * s, i[7] += r * f, i[10] += s *
							s, i[11] += s * f, i[15] += f * f
					}
					return i[4] = i[1], i[8] = i[2], i[9] = i[6], i[12] = i[3], i[13] = i[7], i[14] = i[
					11], {
						R: i,
						m: o,
						N: a
					}
				}

				function estats(e) {
					const {
						R: t
					} = e, {
						m: r
					} = e, {
						N: i
					} = e, a = r[0], s = r[1], f = r[2], l = r[3], c = 0 == i ? 0 : 1 / i, u = [t[0] - a *
						a * c, t[1] - a * s * c, t[2] - a * f * c, t[3] - a * l * c, t[4] - s * a * c,
						t[5] - s * s * c, t[6] - s * f * c, t[7] - s * l * c, t[8] - f * a * c, t[9] -
						f * s * c, t[10] - f * f * c, t[11] - f * l * c, t[12] - l * a * c, t[13] - l *
						s * c, t[14] - l * f * c, t[15] - l * l * c
					], h = u, d = o;
					let A = [Math.random(), Math.random(), Math.random(), Math.random()],
						g = 0,
						p = 0;
					if (0 != i)
						for (let e = 0; e < 16 && (A = d.multVec(h, A), p = Math.sqrt(d.dot(A, A)), A = d
								.sml(1 / p, A), !(0 != e && Math.abs(p - g) < 1e-9)); e++) g = p;
					const m = [a * c, s * c, f * c, l * c];
					return {
						Cov: u,
						q: m,
						e: A,
						L: g,
						eMq255: d.dot(d.sml(255, m), A),
						eMq: d.dot(A, m),
						rgba: (Math.round(255 * m[3]) << 24 | Math.round(255 * m[2]) << 16 | Math.round(
							255 * m[1]) << 8 | Math.round(255 * m[0]) << 0) >>> 0
					}
				}
				var o = {
					multVec: (e, t) => [e[0] * t[0] + e[1] * t[1] + e[2] * t[2] + e[3] * t[3], e[4] * t[
							0] + e[5] * t[1] + e[6] * t[2] + e[7] * t[3], e[8] * t[0] + e[9] * t[
						1] + e[10] * t[2] + e[11] * t[3], e[12] * t[0] + e[13] * t[1] + e[14] * t[
						2] + e[15] * t[3]
					],
					dot: (e, t) => e[0] * t[0] + e[1] * t[1] + e[2] * t[2] + e[3] * t[3],
					sml: (e, t) => [e * t[0], e * t[1], e * t[2], e * t[3]]
				};
				UPNG.encode = function encode(e, t, r, i, o, a, s) {
						null == i && (i = 0), null == s && (s = !1);
						const f = compress(e, t, r, i, [!1, !1, !1, 0, s, !1]);
						return compressPNG(f, -1), _main(f, t, r, o, a)
					}, UPNG.encodeLL = function encodeLL(e, t, r, i, o, a, s, f) {
						const l = {
								ctype: 0 + (1 == i ? 0 : 2) + (0 == o ? 0 : 4),
								depth: a,
								frames: []
							},
							c = (i + o) * a,
							u = c * t;
						for (let i = 0; i < e.length; i++) l.frames.push({
							rect: {
								x: 0,
								y: 0,
								width: t,
								height: r
							},
							img: new Uint8Array(e[i]),
							blend: 0,
							dispose: 1,
							bpp: Math.ceil(c / 8),
							bpl: Math.ceil(u / 8)
						});
						return compressPNG(l, 0, !0), _main(l, t, r, s, f)
					}, UPNG.encode.compress = compress, UPNG.encode.dither = dither, UPNG.quantize =
					quantize, UPNG.quantize.getKDtree = getKDtree, UPNG.quantize.getNearest = getNearest
			}();
			const t = {
				toArrayBuffer(e, r) {
					const i = e.width,
						o = e.height,
						a = i << 2,
						s = e.getContext("2d").getImageData(0, 0, i, o),
						f = new Uint32Array(s.data.buffer),
						l = (32 * i + 31) / 32 << 2,
						c = l * o,
						u = 122 + c,
						h = new ArrayBuffer(u),
						d = new DataView(h),
						A = 1 << 20;
					let g, p, m, w, v = A,
						b = 0,
						y = 0,
						E = 0;

					function set16(e) {
						d.setUint16(y, e, !0), y += 2
					}

					function set32(e) {
						d.setUint32(y, e, !0), y += 4
					}

					function seek(e) {
						y += e
					}
					set16(19778), set32(u), seek(4), set32(122), set32(108), set32(i), set32(-o >>> 0),
						set16(1), set16(32), set32(3), set32(c), set32(2835), set32(2835), seek(8),
						set32(16711680), set32(65280), set32(255), set32(4278190080), set32(1466527264),
						function convert() {
							for (; b < o && v > 0;) {
								for (w = 122 + b * l, g = 0; g < a;) v--, p = f[E++], m = p >>> 24, d
									.setUint32(w + g, p << 8 | m), g += 4;
								b++
							}
							E < f.length ? (v = A, setTimeout(convert, t._dly)) : r(h)
						}()
				},
				toBlob(e, t) {
					this.toArrayBuffer(e, e => {
						t(new Blob([e], {
							type: "image/bmp"
						}))
					})
				},
				_dly: 9
			};
			var r = {
					CHROME: "CHROME",
					FIREFOX: "FIREFOX",
					DESKTOP_SAFARI: "DESKTOP_SAFARI",
					IE: "IE",
					IOS: "IOS",
					ETC: "ETC"
				},
				i = {
					[r.CHROME]: 16384,
					[r.FIREFOX]: 11180,
					[r.DESKTOP_SAFARI]: 16384,
					[r.IE]: 8192,
					[r.IOS]: 4096,
					[r.ETC]: 8192
				};
			const o = "undefined" != typeof window,
				a = "undefined" != typeof WorkerGlobalScope && self instanceof WorkerGlobalScope,
				s = o && window.cordova && window.cordova.require && window.cordova.require(
					"cordova/modulemapper"),
				CustomFile = (o || a) && (s && s.getOriginalSymbol(window, "File") || "undefined" !=
					typeof File && File),
				CustomFileReader = (o || a) && (s && s.getOriginalSymbol(window, "FileReader") ||
					"undefined" != typeof FileReader && FileReader);

			function getFilefromDataUrl(e, t, r = Date.now()) {
				return new Promise(i => {
					const o = e.split(","),
						a = o[0].match(/:(.*?);/)[1],
						s = globalThis.atob(o[1]);
					let f = s.length;
					const l = new Uint8Array(f);
					for (; f--;) l[f] = s.charCodeAt(f);
					const c = new Blob([l], {
						type: a
					});
					c.name = t, c.lastModified = r, i(c)
				})
			}

			function getDataUrlFromFile(e) {
				return new Promise((t, r) => {
					const i = new CustomFileReader;
					i.onload = () => t(i.result), i.onerror = e => r(e), i.readAsDataURL(e)
				})
			}

			function loadImage(e) {
				return new Promise((t, r) => {
					const i = new Image;
					i.onload = () => t(i), i.onerror = e => r(e), i.src = e
				})
			}

			function getBrowserName() {
				if (void 0 !== getBrowserName.cachedResult) return getBrowserName.cachedResult;
				let e = r.ETC;
				const {
					userAgent: t
				} = navigator;
				return /Chrom(e|ium)/i.test(t) ? e = r.CHROME : /iP(ad|od|hone)/i.test(t) && /WebKit/i.test(
						t) ? e = r.IOS : /Safari/i.test(t) ? e = r.DESKTOP_SAFARI : /Firefox/i.test(t) ? e =
					r.FIREFOX : (/MSIE/i.test(t) || !0 == !!document.documentMode) && (e = r.IE),
					getBrowserName.cachedResult = e, getBrowserName.cachedResult
			}

			function approximateBelowMaximumCanvasSizeOfBrowser(e, t) {
				const r = getBrowserName(),
					o = i[r];
				let a = e,
					s = t,
					f = a * s;
				const l = a > s ? s / a : a / s;
				for (; f > o * o;) {
					const e = (o + a) / 2,
						t = (o + s) / 2;
					e < t ? (s = t, a = t * l) : (s = e * l, a = e), f = a * s
				}
				return {
					width: a,
					height: s
				}
			}

			function getNewCanvasAndCtx(e, t) {
				let r, i;
				try {
					if (r = new OffscreenCanvas(e, t), i = r.getContext("2d"), null === i) throw new Error(
						"getContext of OffscreenCanvas returns null")
				} catch (e) {
					r = document.createElement("canvas"), i = r.getContext("2d")
				}
				return r.width = e, r.height = t, [r, i]
			}

			function drawImageInCanvas(e, t) {
				const {
					width: r,
					height: i
				} = approximateBelowMaximumCanvasSizeOfBrowser(e.width, e.height), [o, a] =
					getNewCanvasAndCtx(r, i);
				return t && /jpe?g/.test(t) && (a.fillStyle = "white", a.fillRect(0, 0, o.width, o.height)),
					a.drawImage(e, 0, 0, o.width, o.height), o
			}

			function isIOS() {
				return void 0 !== isIOS.cachedResult || (isIOS.cachedResult = ["iPad Simulator",
						"iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"
					].includes(navigator.platform) || navigator.userAgent.includes("Mac") &&
					"undefined" != typeof document && "ontouchend" in document), isIOS.cachedResult
			}

			function drawFileInCanvas(e, t = {}) {
				return new Promise(function(i, o) {
					let a, s;
					var $Try_2_Post = function() {
							try {
								return s = drawImageInCanvas(a, t.fileType || e.type), i([a, s])
							} catch (e) {
								return o(e)
							}
						},
						$Try_2_Catch = function(t) {
							try {
								0;
								var $Try_3_Catch = function(e) {
									try {
										throw e
									} catch (e) {
										return o(e)
									}
								};
								try {
									let t;
									return getDataUrlFromFile(e).then(function(e) {
										try {
											return t = e, loadImage(t).then(function(e) {
												try {
													return a = e,
														function() {
															try {
																return $Try_2_Post()
															} catch (e) {
																return o(e)
															}
														}()
												} catch (e) {
													return $Try_3_Catch(e)
												}
											}, $Try_3_Catch)
										} catch (e) {
											return $Try_3_Catch(e)
										}
									}, $Try_3_Catch)
								} catch (e) {
									$Try_3_Catch(e)
								}
							} catch (e) {
								return o(e)
							}
						};
					try {
						if (isIOS() || [r.DESKTOP_SAFARI, r.MOBILE_SAFARI].includes(
							getBrowserName())) throw new Error(
							"Skip createImageBitmap on IOS and Safari");
						return createImageBitmap(e).then(function(e) {
							try {
								return a = e, $Try_2_Post()
							} catch (e) {
								return $Try_2_Catch()
							}
						}, $Try_2_Catch)
					} catch (e) {
						$Try_2_Catch()
					}
				})
			}

			function canvasToFile(e, r, i, o, a = 1) {
				return new Promise(function(s, f) {
					let l;
					if ("image/png" === r) {
						let c, u, h;
						return c = e.getContext("2d"), {
							data: u
						} = c.getImageData(0, 0, e.width, e.height), h = UPNG.encode([u.buffer],
							e.width, e.height, 4096 * a), l = new Blob([h], {
							type: r
						}), l.name = i, l.lastModified = o, $If_4.call(this)
					} {
						if ("image/bmp" === r) return new Promise(r => t.toBlob(e, r)).then(
							function(e) {
								try {
									return l = e, l.name = i, l.lastModified = o, $If_5
										.call(this)
								} catch (e) {
									return f(e)
								}
							}.bind(this), f); {
							if ("function" == typeof OffscreenCanvas &&
								e instanceof OffscreenCanvas) return e.convertToBlob({
								type: r,
								quality: a
							}).then(function(e) {
								try {
									return l = e, l.name = i, l.lastModified = o, $If_6
										.call(this)
								} catch (e) {
									return f(e)
								}
							}.bind(this), f); {
								let d;
								return d = e.toDataURL(r, a), getFilefromDataUrl(d, i, o).then(
									function(e) {
										try {
											return l = e, $If_6.call(this)
										} catch (e) {
											return f(e)
										}
									}.bind(this), f)
							}

							function $If_6() {
								return $If_5.call(this)
							}
						}

						function $If_5() {
							return $If_4.call(this)
						}
					}

					function $If_4() {
						return s(l)
					}
				})
			}

			function cleanupCanvasMemory(e) {
				e.width = 0, e.height = 0
			}

			function isAutoOrientationInBrowser() {
				return new Promise(function(e, t) {
					let r, i, o, a, s;
					return void 0 !== isAutoOrientationInBrowser.cachedResult ? e(
						isAutoOrientationInBrowser.cachedResult) : (r =
						"",
						getFilefromDataUrl(
							"",
							"test.jpg", Date.now()).then(function(r) {
							try {
								return i = r, drawFileInCanvas(i).then(function(r) {
									try {
										return o = r[1], canvasToFile(o, i.type, i
											.name, i.lastModified).then(
											function(r) {
												try {
													return a = r,
														cleanupCanvasMemory(o),
														drawFileInCanvas(a)
														.then(function(r) {
															try {
																return s =
																	r[0],
																	isAutoOrientationInBrowser
																	.cachedResult =
																	1 === s
																	.width &&
																	2 === s
																	.height,
																	e(isAutoOrientationInBrowser
																		.cachedResult
																		)
															} catch (e) {
																return t(e)
															}
														}, t)
												} catch (e) {
													return t(e)
												}
											}, t)
									} catch (e) {
										return t(e)
									}
								}, t)
							} catch (e) {
								return t(e)
							}
						}, t))
				})
			}

			function getExifOrientation(e) {
				return new Promise((t, r) => {
					const i = new CustomFileReader;
					i.onload = e => {
						const r = new DataView(e.target.result);
						if (65496 != r.getUint16(0, !1)) return t(-2);
						const i = r.byteLength;
						let o = 2;
						for (; o < i;) {
							if (r.getUint16(o + 2, !1) <= 8) return t(-1);
							const e = r.getUint16(o, !1);
							if (o += 2, 65505 == e) {
								if (1165519206 != r.getUint32(o += 2, !1)) return t(-1);
								const e = 18761 == r.getUint16(o += 6, !1);
								o += r.getUint32(o + 4, e);
								const i = r.getUint16(o, e);
								o += 2;
								for (let a = 0; a < i; a++)
									if (274 == r.getUint16(o + 12 * a, e)) return t(r.getUint16(
										o + 12 * a + 8, e))
							} else {
								if (65280 != (65280 & e)) break;
								o += r.getUint16(o, !1)
							}
						}
						return t(-1)
					}, i.onerror = e => r(e), i.readAsArrayBuffer(e)
				})
			}

			function handleMaxWidthOrHeight(e, t) {
				const {
					width: r
				} = e, {
					height: i
				} = e, {
					maxWidthOrHeight: o
				} = t;
				let a, s = e;
				return isFinite(o) && (r > o || i > o) && ([s, a] = getNewCanvasAndCtx(r, i), r > i ? (s
						.width = o, s.height = i / r * o) : (s.width = r / i * o, s.height = o), a
					.drawImage(e, 0, 0, s.width, s.height), cleanupCanvasMemory(e)), s
			}

			function followExifOrientation(e, t) {
				const {
					width: r
				} = e, {
					height: i
				} = e, [o, a] = getNewCanvasAndCtx(r, i);
				switch (t > 4 && t < 9 ? (o.width = i, o.height = r) : (o.width = r, o.height = i), t) {
					case 2:
						a.transform(-1, 0, 0, 1, r, 0);
						break;
					case 3:
						a.transform(-1, 0, 0, -1, r, i);
						break;
					case 4:
						a.transform(1, 0, 0, -1, 0, i);
						break;
					case 5:
						a.transform(0, 1, 1, 0, 0, 0);
						break;
					case 6:
						a.transform(0, 1, -1, 0, i, 0);
						break;
					case 7:
						a.transform(0, -1, -1, 0, i, r);
						break;
					case 8:
						a.transform(0, -1, 1, 0, 0, r)
				}
				return a.drawImage(e, 0, 0, r, i), cleanupCanvasMemory(e), o
			}

			function compress(e, t, r = 0) {
				return new Promise(function(i, o) {
					let a, s, f, l, c, u, h, d, A, g, p, m, w, v, b, y, E, F, _, B;

					function incProgress(e = 5) {
						if (t.signal && t.signal.aborted) throw t.signal.reason;
						a += e, t.onProgress(Math.min(a, 100))
					}

					function setProgress(e) {
						if (t.signal && t.signal.aborted) throw t.signal.reason;
						a = Math.min(Math.max(e, a), 100), t.onProgress(a)
					}
					return a = r, s = t.maxIteration || 10, f = 1024 * t.maxSizeMB * 1024,
						incProgress(), drawFileInCanvas(e, t).then(function(r) {
							try {
								return [, l] = r, incProgress(), c = handleMaxWidthOrHeight(l,
									t), incProgress(), new Promise(function(r, i) {
									var o;
									if (!(o = t.exifOrientation))
									return getExifOrientation(e).then(function(e) {
											try {
												return o = e, $If_2.call(this)
											} catch (e) {
												return i(e)
											}
										}.bind(this), i);

									function $If_2() {
										return r(o)
									}
									return $If_2.call(this)
								}).then(function(r) {
									try {
										return u = r, incProgress(),
											isAutoOrientationInBrowser().then(function(
												r) {
												try {
													return h = r ? c :
														followExifOrientation(c, u),
														incProgress(), d = t
														.initialQuality || 1, A = t
														.fileType || e.type,
														canvasToFile(h, A, e.name, e
															.lastModified, d).then(
															function(r) {
																try {
																	{
																		if (g = r,
																			incProgress(),
																			p = g
																			.size >
																			f, m = g
																			.size >
																			e.size,
																			!p && !m
																			) return setProgress(
																				100
																				),
																			i(g);
																		var a;

																		function $Loop_3() {
																			if (s--
																				&& (b >
																					f ||
																					b >
																					w
																					)
																				) {
																				let t,
																					r;
																				return t =
																					B ?
																					.95 *
																					_
																					.width :
																					_
																					.width,
																					r =
																					B ?
																					.95 *
																					_
																					.height :
																					_
																					.height,
																					[E,
																						F] =
																					getNewCanvasAndCtx(
																						t,
																						r
																						),
																					F
																					.drawImage(
																						_,
																						0,
																						0,
																						t,
																						r
																						),
																					d *=
																					"image/png" ===
																					A ?
																					.85 :
																					.95,
																					canvasToFile(
																						E,
																						A,
																						e
																						.name,
																						e
																						.lastModified,
																						d
																						)
																					.then(
																						function(
																							e
																							) {
																							try {
																								return y =
																									e,
																									cleanupCanvasMemory(
																										_
																										),
																									_ =
																									E,
																									b =
																									y
																									.size,
																									setProgress(
																										Math
																										.min(
																											99,
																											Math
																											.floor(
																												(v -
																													b) /
																												(v -
																													f) *
																												100
																												)
																											)
																										),
																									$Loop_3
																							} catch (
																								e
																								) {
																								return o(
																									e
																									)
																							}
																						},
																						o
																						)
																			}
																			return [
																				1]
																		}
																		return w = e
																			.size,
																			v = g
																			.size,
																			b = v,
																			_ = h,
																			B = !t
																			.alwaysKeepResolution &&
																			p, (a =
																				function(
																					e
																					) {
																					for (; e;) {
																						if (e
																							.then
																							)
																							return void e
																								.then(
																									a,
																									o
																									);
																						try {
																							if (e
																								.pop
																								) {
																								if (e
																									.length
																									)
																									return e
																										.pop() ?
																										$Loop_3_exit
																										.call(
																											this
																											) :
																										e;
																								e = $Loop_3
																							} else
																								e =
																								e
																								.call(
																									this
																									)
																						} catch (
																							e
																							) {
																							return o(
																								e
																								)
																						}
																					}
																				}
																				.bind(
																					this
																					)
																				)(
																				$Loop_3
																				);

																		function $Loop_3_exit() {
																			return cleanupCanvasMemory(
																					_
																					),
																				cleanupCanvasMemory(
																					E
																					),
																				cleanupCanvasMemory(
																					c
																					),
																				cleanupCanvasMemory(
																					h
																					),
																				cleanupCanvasMemory(
																					l
																					),
																				setProgress(
																					100
																					),
																				i(y)
																		}
																	}
																} catch (u) {
																	return o(u)
																}
															}.bind(this), o)
												} catch (e) {
													return o(e)
												}
											}.bind(this), o)
									} catch (e) {
										return o(e)
									}
								}.bind(this), o)
							} catch (e) {
								return o(e)
							}
						}.bind(this), o)
				})
			}
			const f =
				"\nlet scriptImported = false\nself.addEventListener('message', async (e) => {\n  const { file, id, imageCompressionLibUrl, options } = e.data\n  options.onProgress = (progress) => self.postMessage({ progress, id })\n  try {\n    if (!scriptImported) {\n      // console.log('[worker] importScripts', imageCompressionLibUrl)\n      self.importScripts(imageCompressionLibUrl)\n      scriptImported = true\n    }\n    // console.log('[worker] self', self)\n    const compressedFile = await imageCompression(file, options)\n    self.postMessage({ file: compressedFile, id })\n  } catch (e) {\n    // console.error('[worker] error', e)\n    self.postMessage({ error: e.message + '\\n' + e.stack, id })\n  }\n})\n";
			let l;

			function compressOnWebWorker(e, t) {
				return new Promise((r, i) => {
					l || (l = function createWorkerScriptURL(e) {
						const t = [];
						return "function" == typeof e ? t.push(`(${e})()`) : t.push(e), URL
							.createObjectURL(new Blob(t))
					}(f));
					const o = new Worker(l);
					o.addEventListener("message", function handler(e) {
						if (t.signal && t.signal.aborted) o.terminate();
						else if (void 0 === e.data.progress) {
							if (e.data.error) return i(new Error(e.data.error)), void o
								.terminate();
							r(e.data.file), o.terminate()
						} else t.onProgress(e.data.progress)
					}), o.addEventListener("error", i), t.signal && t.signal.addEventListener(
						"abort", () => {
							i(t.signal.reason), o.terminate()
						}), o.postMessage({
						file: e,
						imageCompressionLibUrl: t.libURL,
						options: {
							...t,
							onProgress: void 0,
							signal: void 0
						}
					})
				})
			}

			function imageCompression(e, t) {
				return new Promise(function(r, i) {
					let o, a, s, f, l, c;
					if (o = {
							...t
						}, s = 0, {
							onProgress: f
						} = o, o.maxSizeMB = o.maxSizeMB || Number.POSITIVE_INFINITY, l =
						"boolean" != typeof o.useWebWorker || o.useWebWorker, delete o.useWebWorker,
						o.onProgress = e => {
							s = e, "function" == typeof f && f(s)
						}, !(1 || e instanceof Blob || e instanceof CustomFile)) return i(new Error(
						"The file given is not an instance of Blob or File"));
					if (!/^image/.test(e.type)) return i(new Error(
						"The file given is not an image"));
					if (c = "undefined" != typeof WorkerGlobalScope &&
						self instanceof WorkerGlobalScope, !l || "function" != typeof Worker || c)
						return compress(e, o).then(function(e) {
							try {
								return a = e, $If_4.call(this)
							} catch (e) {
								return i(e)
							}
						}.bind(this), i);
					var u = function() {
							try {
								return $If_4.call(this)
							} catch (e) {
								return i(e)
							}
						}.bind(this),
						$Try_1_Catch = function(t) {
							try {
								return compress(e, o).then(function(e) {
									try {
										return a = e, u()
									} catch (e) {
										return i(e)
									}
								}, i)
							} catch (e) {
								return i(e)
							}
						};
					try {
						return o.libURL = o.libURL ||
							"https://cdn.bootcdn.net/ajax/libs/browser-image-compression/2.0.2/browser-image-compression.js",
							compressOnWebWorker(e, o).then(function(e) {
								try {
									return a = e, u()
								} catch (e) {
									return $Try_1_Catch()
								}
							}, $Try_1_Catch)
					} catch (e) {
						$Try_1_Catch()
					}

					function $If_4() {
						try {
							a.name = e.name, a.lastModified = e.lastModified
						} catch (e) {}
						try {
							o.preserveExif && "image/jpeg" === e.type && (!o.fileType || o
								.fileType && o.fileType === e.type) && (a =
								copyExifWithoutOrientation(e, a))
						} catch (e) {}
						return r(a)
					}
				})
			}
			return imageCompression.getDataUrlFromFile = getDataUrlFromFile, imageCompression
				.getFilefromDataUrl = getFilefromDataUrl, imageCompression.loadImage = loadImage,
				imageCompression.drawImageInCanvas = drawImageInCanvas, imageCompression.drawFileInCanvas =
				drawFileInCanvas, imageCompression.canvasToFile = canvasToFile, imageCompression
				.getExifOrientation = getExifOrientation, imageCompression.handleMaxWidthOrHeight =
				handleMaxWidthOrHeight, imageCompression.followExifOrientation = followExifOrientation,
				imageCompression.cleanupCanvasMemory = cleanupCanvasMemory, imageCompression
				.isAutoOrientationInBrowser = isAutoOrientationInBrowser, imageCompression
				.approximateBelowMaximumCanvasSizeOfBrowser = approximateBelowMaximumCanvasSizeOfBrowser,
				imageCompression.copyExifWithoutOrientation = copyExifWithoutOrientation, imageCompression
				.getBrowserName = getBrowserName, imageCompression.version = "2.0.2", imageCompression
		});
		return {
			compress: function(file, option) {
				return imageCompression(file, option)
			}
		}
	}();
	UE.dialog = function() {
		return {
			loadingPlaceholder: function(me) {
				var loadingId = "loading_" + (+new Date).toString(36);
				me.focus();
				me.execCommand("inserthtml", '<img class="uep-loading" id="' + loadingId + '" src="' + me
					.options.themePath + me.options.theme + '/images/spacer.gif">');
				return loadingId
			},
			removeLoadingPlaceholder: function(me, loadingId) {
				var loader = me.document.getElementById(loadingId);
				if (loader) {
					domUtils.remove(loader, false)
				}
			},
			tipError: function(me, title) {
				me.fireEvent("showmessage", {
					content: title,
					type: "error",
					timeout: 4e3
				})
			}
		}
	}();
	var filterWord = UE.filterWord = function() {
		function isWordDocument(str) {
			return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/gi.test(str)
		}

		function transUnit(v) {
			v = v.replace(/[\d.]+\w+/g, function(m) {
				return utils.transUnitToPx(m)
			});
			return v
		}

		function filterPasteWord(str) {
			return str.replace(/[\t\r\n]+/g, " ").replace(/<!--[\s\S]*?-->/gi, "").replace(
					/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi,
					function(str) {
						if (browser.opera) {
							return ""
						}
						try {
							if (/Bitmap/i.test(str)) {
								return ""
							}
							var width = str.match(/width:([ \d.]*p[tx])/i)[1],
								height = str.match(/height:([ \d.]*p[tx])/i)[1],
								src = str.match(/src=\s*"([^"]*)"/i)[1];
							return '<img width="' + transUnit(width) + '" height="' + transUnit(height) +
								'" src="' + src + '" />'
						} catch (e) {
							return ""
						}
					}).replace(/<\/?div[^>]*>/g, "").replace(/v:\w+=(["']?)[^'"]+\1/g, "").replace(
					/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi,
					"").replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>")
				.replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/gi, function(str, name, marks, val) {
					return name == "class" && val == "MsoListParagraph" ? str : ""
				}).replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi, function(a, b, c) {
					return c.replace(/[\t\r\n ]+/g, " ")
				}).replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function(str, tag, tmp, style) {
					var n = [],
						s = style.replace(/^\s+|\s+$/, "").replace(/&#39;/g, "'").replace(/&quot;/gi, "'")
						.replace(/[\d.]+(cm|pt)/g, function(str) {
							return utils.transUnitToPx(str)
						}).split(/;\s*/g);
					for (var i = 0, v; v = s[i]; i++) {
						var name, value, parts = v.split(":");
						if (parts.length == 2) {
							name = parts[0].toLowerCase();
							value = parts[1].toLowerCase();
							if (/^(background)\w*/.test(name) && value.replace(/(initial|\s)/g, "")
								.length == 0 || /^(margin)\w*/.test(name) && /^0\w+$/.test(value)) {
								continue
							}
							switch (name) {
								case "mso-padding-alt":
								case "mso-padding-top-alt":
								case "mso-padding-right-alt":
								case "mso-padding-bottom-alt":
								case "mso-padding-left-alt":
								case "mso-margin-alt":
								case "mso-margin-top-alt":
								case "mso-margin-right-alt":
								case "mso-margin-bottom-alt":
								case "mso-margin-left-alt":
								case "mso-height":
								case "mso-width":
								case "mso-vertical-align-alt":
									if (!/<table/.test(tag)) n[i] = name.replace(/^mso-|-alt$/g, "") + ":" +
										transUnit(value);
									continue;
								case "horiz-align":
									n[i] = "text-align:" + value;
									continue;
								case "vert-align":
									n[i] = "vertical-align:" + value;
									continue;
								case "font-color":
								case "mso-foreground":
									n[i] = "color:" + value;
									continue;
								case "mso-background":
								case "mso-highlight":
									n[i] = "background:" + value;
									continue;
								case "mso-default-height":
									n[i] = "min-height:" + transUnit(value);
									continue;
								case "mso-default-width":
									n[i] = "min-width:" + transUnit(value);
									continue;
								case "mso-padding-between-alt":
									n[i] = "border-collapse:separate;border-spacing:" + transUnit(value);
									continue;
								case "text-line-through":
									if (value == "single" || value == "double") {
										n[i] = "text-decoration:line-through"
									}
									continue;
								case "mso-zero-height":
									if (value == "yes") {
										n[i] = "display:none"
									}
									continue;
								case "margin":
									if (!/[1-9]/.test(value)) {
										continue
									}
							}
							if (/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?:decor|trans)|top-bar|version|vnd|word-break)/
								.test(name) || /text\-indent|padding|margin/.test(name) && /\-[\d.]+/.test(
									value)) {
								continue
							}
							n[i] = name + ":" + parts[1]
						}
					}
					return tag + (n.length ? ' style="' + n.join(";").replace(/;{2,}/g, ";") + '"' : "")
				})
		}
		return function(html) {
			return isWordDocument(html) ? filterPasteWord(html) : html
		}
	}();
	(function() {
		var uNode = UE.uNode = function(obj) {
			this.type = obj.type;
			this.data = obj.data;
			this.tagName = obj.tagName;
			this.parentNode = obj.parentNode;
			this.attrs = obj.attrs || {};
			this.children = obj.children
		};
		var notTransAttrs = {
			href: 1,
			src: 1,
			_src: 1,
			_href: 1,
			cdata_data: 1
		};
		var notTransTagName = {
			style: 1,
			script: 1
		};
		var indentChar = "    ",
			breakChar = "\n";

		function insertLine(arr, current, begin) {
			arr.push(breakChar);
			return current + (begin ? 1 : -1)
		}

		function insertIndent(arr, current) {
			for (var i = 0; i < current; i++) {
				arr.push(indentChar)
			}
		}
		uNode.createElement = function(html) {
			if (/[<>]/.test(html)) {
				return UE.htmlparser(html).children[0]
			} else {
				return new uNode({
					type: "element",
					children: [],
					tagName: html
				})
			}
		};
		uNode.createText = function(data, noTrans) {
			return new UE.uNode({
				type: "text",
				data: noTrans ? data : utils.unhtml(data || "")
			})
		};

		function nodeToHtml(node, arr, formatter, current) {
			switch (node.type) {
				case "root":
					for (var i = 0, ci; ci = node.children[i++];) {
						if (formatter && ci.type == "element" && !dtd.$inlineWithA[ci.tagName] && i > 1) {
							insertLine(arr, current, true);
							insertIndent(arr, current)
						}
						nodeToHtml(ci, arr, formatter, current)
					}
					break;
				case "text":
					isText(node, arr);
					break;
				case "element":
					isElement(node, arr, formatter, current);
					break;
				case "comment":
					isComment(node, arr, formatter)
			}
			return arr
		}

		function isText(node, arr) {
			if (node.parentNode.tagName == "pre") {
				arr.push(node.data)
			} else {
				arr.push(notTransTagName[node.parentNode.tagName] ? utils.html(node.data) : node.data.replace(
					/[ ]{2}/g, " &nbsp;"))
			}
		}

		function isElement(node, arr, formatter, current) {
			var attrhtml = "";
			if (node.attrs) {
				attrhtml = [];
				var attrs = node.attrs;
				for (var a in attrs) {
					attrhtml.push(a + (attrs[a] !== undefined ? '="' + (notTransAttrs[a] ? utils.html(attrs[a])
						.replace(/["]/g, function(a) {
							return "&quot;"
						}) : utils.unhtml(attrs[a])) + '"' : ""))
				}
				attrhtml = attrhtml.join(" ")
			}
			arr.push("<" + node.tagName + (attrhtml ? " " + attrhtml : "") + (dtd.$empty[node.tagName] ? "/" :
				"") + ">");
			if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != "pre") {
				if (node.children && node.children.length) {
					current = insertLine(arr, current, true);
					insertIndent(arr, current)
				}
			}
			if (node.children && node.children.length) {
				for (var i = 0, ci; ci = node.children[i++];) {
					if (formatter && ci.type == "element" && !dtd.$inlineWithA[ci.tagName] && i > 1) {
						insertLine(arr, current);
						insertIndent(arr, current)
					}
					nodeToHtml(ci, arr, formatter, current)
				}
			}
			if (!dtd.$empty[node.tagName]) {
				if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != "pre") {
					if (node.children && node.children.length) {
						current = insertLine(arr, current);
						insertIndent(arr, current)
					}
				}
				arr.push("</" + node.tagName + ">")
			}
		}

		function isComment(node, arr) {
			arr.push("\x3c!--" + node.data + "--\x3e")
		}

		function getNodeById(root, id) {
			var node;
			if (root.type == "element" && root.getAttr("id") == id) {
				return root
			}
			if (root.children && root.children.length) {
				for (var i = 0, ci; ci = root.children[i++];) {
					if (node = getNodeById(ci, id)) {
						return node
					}
				}
			}
		}

		function getNodesByTagName(node, tagName, arr) {
			if (node.type == "element" && node.tagName == tagName) {
				arr.push(node)
			}
			if (node.children && node.children.length) {
				for (var i = 0, ci; ci = node.children[i++];) {
					getNodesByTagName(ci, tagName, arr)
				}
			}
		}

		function nodeTraversal(root, fn) {
			if (root.children && root.children.length) {
				for (var i = 0, ci; ci = root.children[i];) {
					nodeTraversal(ci, fn);
					if (ci.parentNode) {
						if (ci.children && ci.children.length) {
							fn(ci)
						}
						if (ci.parentNode) i++
					}
				}
			} else {
				fn(root)
			}
		}
		uNode.prototype = {
			toHtml: function(formatter) {
				var arr = [];
				nodeToHtml(this, arr, formatter, 0);
				return arr.join("")
			},
			innerHTML: function(htmlstr) {
				if (this.type != "element" || dtd.$empty[this.tagName]) {
					return this
				}
				if (utils.isString(htmlstr)) {
					if (this.children) {
						for (var i = 0, ci; ci = this.children[i++];) {
							ci.parentNode = null
						}
					}
					this.children = [];
					var tmpRoot = UE.htmlparser(htmlstr);
					for (var i = 0, ci; ci = tmpRoot.children[i++];) {
						this.children.push(ci);
						ci.parentNode = this
					}
					return this
				} else {
					var tmpRoot = new UE.uNode({
						type: "root",
						children: this.children
					});
					return tmpRoot.toHtml()
				}
			},
			innerText: function(textStr, noTrans) {
				if (this.type != "element" || dtd.$empty[this.tagName]) {
					return this
				}
				if (textStr) {
					if (this.children) {
						for (var i = 0, ci; ci = this.children[i++];) {
							ci.parentNode = null
						}
					}
					this.children = [];
					this.appendChild(uNode.createText(textStr, noTrans));
					return this
				} else {
					return this.toHtml().replace(/<[^>]+>/g, "")
				}
			},
			getData: function() {
				if (this.type == "element") return "";
				return this.data
			},
			firstChild: function() {
				return this.children ? this.children[0] : null
			},
			lastChild: function() {
				return this.children ? this.children[this.children.length - 1] : null
			},
			previousSibling: function() {
				var parent = this.parentNode;
				for (var i = 0, ci; ci = parent.children[i]; i++) {
					if (ci === this) {
						return i == 0 ? null : parent.children[i - 1]
					}
				}
			},
			nextSibling: function() {
				var parent = this.parentNode;
				for (var i = 0, ci; ci = parent.children[i++];) {
					if (ci === this) {
						return parent.children[i]
					}
				}
			},
			replaceChild: function(target, source) {
				if (this.children) {
					if (target.parentNode) {
						target.parentNode.removeChild(target)
					}
					for (var i = 0, ci; ci = this.children[i]; i++) {
						if (ci === source) {
							this.children.splice(i, 1, target);
							source.parentNode = null;
							target.parentNode = this;
							return target
						}
					}
				}
			},
			appendChild: function(node) {
				if (this.type == "root" || this.type == "element" && !dtd.$empty[this.tagName]) {
					if (!this.children) {
						this.children = []
					}
					if (node.parentNode) {
						node.parentNode.removeChild(node)
					}
					for (var i = 0, ci; ci = this.children[i]; i++) {
						if (ci === node) {
							this.children.splice(i, 1);
							break
						}
					}
					this.children.push(node);
					node.parentNode = this;
					return node
				}
			},
			insertBefore: function(target, source) {
				if (this.children) {
					if (target.parentNode) {
						target.parentNode.removeChild(target)
					}
					for (var i = 0, ci; ci = this.children[i]; i++) {
						if (ci === source) {
							this.children.splice(i, 0, target);
							target.parentNode = this;
							return target
						}
					}
				}
			},
			insertAfter: function(target, source) {
				if (this.children) {
					if (target.parentNode) {
						target.parentNode.removeChild(target)
					}
					for (var i = 0, ci; ci = this.children[i]; i++) {
						if (ci === source) {
							this.children.splice(i + 1, 0, target);
							target.parentNode = this;
							return target
						}
					}
				}
			},
			removeChild: function(node, keepChildren) {
				if (this.children) {
					for (var i = 0, ci; ci = this.children[i]; i++) {
						if (ci === node) {
							this.children.splice(i, 1);
							ci.parentNode = null;
							if (keepChildren && ci.children && ci.children.length) {
								for (var j = 0, cj; cj = ci.children[j]; j++) {
									this.children.splice(i + j, 0, cj);
									cj.parentNode = this
								}
							}
							return ci
						}
					}
				}
			},
			getAttr: function(attrName) {
				return this.attrs && this.attrs[attrName.toLowerCase()]
			},
			setAttr: function(attrName, attrVal) {
				if (!attrName) {
					delete this.attrs;
					return
				}
				if (!this.attrs) {
					this.attrs = {}
				}
				if (utils.isObject(attrName)) {
					for (var a in attrName) {
						if (!attrName[a]) {
							delete this.attrs[a]
						} else {
							this.attrs[a.toLowerCase()] = attrName[a]
						}
					}
				} else {
					if (!attrVal) {
						delete this.attrs[attrName]
					} else {
						this.attrs[attrName.toLowerCase()] = attrVal
					}
				}
			},
			getIndex: function() {
				var parent = this.parentNode;
				for (var i = 0, ci; ci = parent.children[i]; i++) {
					if (ci === this) {
						return i
					}
				}
				return -1
			},
			getNodeById: function(id) {
				var node;
				if (this.children && this.children.length) {
					for (var i = 0, ci; ci = this.children[i++];) {
						if (node = getNodeById(ci, id)) {
							return node
						}
					}
				}
			},
			getNodesByTagName: function(tagNames) {
				tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, " ").split(" ");
				var arr = [],
					me = this;
				utils.each(tagNames, function(tagName) {
					if (me.children && me.children.length) {
						for (var i = 0, ci; ci = me.children[i++];) {
							getNodesByTagName(ci, tagName, arr)
						}
					}
				});
				return arr
			},
			getStyle: function(name) {
				var cssStyle = this.getAttr("style");
				if (!cssStyle) {
					return ""
				}
				var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+)", "i");
				var match = cssStyle.match(reg);
				if (match && match[0]) {
					return match[2]
				}
				return ""
			},
			setStyle: function(name, val) {
				function exec(name, val) {
					var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+;?)", "gi");
					cssStyle = cssStyle.replace(reg, "$1");
					if (val) {
						cssStyle = name + ":" + utils.unhtml(val) + ";" + cssStyle
					}
				}
				var cssStyle = this.getAttr("style");
				if (!cssStyle) {
					cssStyle = ""
				}
				if (utils.isObject(name)) {
					for (var a in name) {
						exec(a, name[a])
					}
				} else {
					exec(name, val)
				}
				this.setAttr("style", utils.trim(cssStyle))
			},
			traversal: function(fn) {
				if (this.children && this.children.length) {
					nodeTraversal(this, fn)
				}
				return this
			}
		}
	})();
	var htmlparser = UE.htmlparser = function(htmlstr, ignoreBlank) {
		var re_tag =
			/<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g,
			re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
		var allowEmptyTags = {
			b: 1,
			code: 1,
			i: 1,
			u: 1,
			strike: 1,
			s: 1,
			tt: 1,
			strong: 1,
			q: 1,
			samp: 1,
			em: 1,
			span: 1,
			sub: 1,
			img: 1,
			sup: 1,
			font: 1,
			big: 1,
			small: 1,
			iframe: 1,
			a: 1,
			br: 1,
			pre: 1
		};
		htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, "g"), "");
		if (!ignoreBlank) {
			htmlstr = htmlstr.replace(new RegExp("[\\r\\t\\n" + (ignoreBlank ? "" : " ") +
				"]*</?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n" + (ignoreBlank ? "" : " ") + "]*", "g"), function(
				a, b) {
				if (b && allowEmptyTags[b.toLowerCase()]) {
					return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, "")
				}
				return a.replace(new RegExp("^[\\r\\n" + (ignoreBlank ? "" : " ") + "]+"), "").replace(
					new RegExp("[\\r\\n" + (ignoreBlank ? "" : " ") + "]+$"), "")
			})
		}
		var notTransAttrs = {
			href: 1,
			src: 1
		};
		var uNode = UE.uNode,
			needParentNode = {
				td: "tr",
				tr: ["tbody", "thead", "tfoot"],
				tbody: "table",
				th: "tr",
				thead: "table",
				tfoot: "table",
				caption: "table",
				li: ["ul", "ol"],
				dt: "dl",
				dd: "dl",
				option: "select"
			},
			needChild = {
				ol: "li",
				ul: "li"
			};

		function text(parent, data) {
			if (needChild[parent.tagName]) {
				var tmpNode = uNode.createElement(needChild[parent.tagName]);
				parent.appendChild(tmpNode);
				tmpNode.appendChild(uNode.createText(data));
				parent = tmpNode
			} else {
				parent.appendChild(uNode.createText(data))
			}
		}

		function element(parent, tagName, htmlattr) {
			var needParentTag;
			if (needParentTag = needParentNode[tagName]) {
				var tmpParent = parent,
					hasParent;
				while (tmpParent.type != "root") {
					if (utils.isArray(needParentTag) ? utils.indexOf(needParentTag, tmpParent.tagName) != -1 :
						needParentTag == tmpParent.tagName) {
						parent = tmpParent;
						hasParent = true;
						break
					}
					tmpParent = tmpParent.parentNode
				}
				if (!hasParent) {
					parent = element(parent, utils.isArray(needParentTag) ? needParentTag[0] : needParentTag)
				}
			}
			var elm = new uNode({
				parentNode: parent,
				type: "element",
				tagName: tagName.toLowerCase(),
				children: dtd.$empty[tagName] ? null : []
			});
			if (htmlattr) {
				var attrs = {},
					match;
				while (match = re_attr.exec(htmlattr)) {
					attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()] ? match[2] || match[
						3] || match[4] : utils.unhtml(match[2] || match[3] || match[4])
				}
				elm.attrs = attrs
			}
			parent.children.push(elm);
			return dtd.$empty[tagName] ? parent : elm
		}

		function comment(parent, data) {
			parent.children.push(new uNode({
				type: "comment",
				data: data,
				parentNode: parent
			}))
		}
		var match, currentIndex = 0,
			nextIndex = 0;
		var root = new uNode({
			type: "root",
			children: []
		});
		var currentParent = root;
		while (match = re_tag.exec(htmlstr)) {
			currentIndex = match.index;
			try {
				if (currentIndex > nextIndex) {
					text(currentParent, htmlstr.slice(nextIndex, currentIndex))
				}
				if (match[3]) {
					if (dtd.$cdata[currentParent.tagName]) {
						text(currentParent, match[0])
					} else {
						currentParent = element(currentParent, match[3].toLowerCase(), match[4])
					}
				} else if (match[1]) {
					if (currentParent.type != "root") {
						if (dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]) {
							text(currentParent, match[0])
						} else {
							var tmpParent = currentParent;
							while (currentParent.type == "element" && currentParent.tagName != match[1]
								.toLowerCase()) {
								currentParent = currentParent.parentNode;
								if (currentParent.type == "root") {
									currentParent = tmpParent;
									throw "break"
								}
							}
							currentParent = currentParent.parentNode
						}
					}
				} else if (match[2]) {
					comment(currentParent, match[2])
				}
			} catch (e) {}
			nextIndex = re_tag.lastIndex
		}
		if (nextIndex < htmlstr.length) {
			text(currentParent, htmlstr.slice(nextIndex))
		}
		return root
	};
	var filterNode = UE.filterNode = function() {
		function filterNode(node, rules) {
			switch (node.type) {
				case "text":
					break;
				case "element":
					var val;
					if (val = rules[node.tagName]) {
						if (val === "-") {
							node.parentNode.removeChild(node)
						} else if (utils.isFunction(val)) {
							var parentNode = node.parentNode,
								index = node.getIndex();
							val(node);
							if (node.parentNode) {
								if (node.children) {
									for (var i = 0, ci; ci = node.children[i];) {
										filterNode(ci, rules);
										if (ci.parentNode) {
											i++
										}
									}
								}
							} else {
								for (var i = index, ci; ci = parentNode.children[i];) {
									filterNode(ci, rules);
									if (ci.parentNode) {
										i++
									}
								}
							}
						} else {
							var attrs = val["$"];
							if (attrs && node.attrs) {
								var tmpAttrs = {},
									tmpVal;
								for (var a in attrs) {
									tmpVal = node.getAttr(a);
									if (a == "style" && utils.isArray(attrs[a])) {
										var tmpCssStyle = [];
										utils.each(attrs[a], function(v) {
											var tmp;
											if (tmp = node.getStyle(v)) {
												tmpCssStyle.push(v + ":" + tmp)
											}
										});
										tmpVal = tmpCssStyle.join(";")
									}
									if (tmpVal) {
										tmpAttrs[a] = tmpVal
									}
								}
								node.attrs = tmpAttrs
							}
							if (node.children) {
								for (var i = 0, ci; ci = node.children[i];) {
									filterNode(ci, rules);
									if (ci.parentNode) {
										i++
									}
								}
							}
						}
					} else {
						if (dtd.$cdata[node.tagName]) {
							node.parentNode.removeChild(node)
						} else {
							var parentNode = node.parentNode,
								index = node.getIndex();
							node.parentNode.removeChild(node, true);
							for (var i = index, ci; ci = parentNode.children[i];) {
								filterNode(ci, rules);
								if (ci.parentNode) {
									i++
								}
							}
						}
					}
					break;
				case "comment":
					node.parentNode.removeChild(node)
			}
		}
		return function(root, rules) {
			if (utils.isEmptyObject(rules)) {
				return root
			}
			var val;
			if (val = rules["-"]) {
				utils.each(val.split(" "), function(k) {
					rules[k] = "-"
				})
			}
			for (var i = 0, ci; ci = root.children[i];) {
				filterNode(ci, rules);
				if (ci.parentNode) {
					i++
				}
			}
			return root
		}
	}();
	UE.plugin = function() {
		var _plugins = {};
		return {
			register: function(pluginName, fn, oldOptionName, afterDisabled) {
				if (oldOptionName && utils.isFunction(oldOptionName)) {
					afterDisabled = oldOptionName;
					oldOptionName = null
				}
				_plugins[pluginName] = {
					optionName: oldOptionName || pluginName,
					execFn: fn,
					afterDisabled: afterDisabled
				}
			},
			load: function(editor) {
				utils.each(_plugins, function(plugin) {
					var _export = plugin.execFn.call(editor);
					if (editor.options[plugin.optionName] !== false) {
						if (_export) {
							utils.each(_export, function(v, k) {
								switch (k.toLowerCase()) {
									case "shortcutkey":
										editor.addshortcutkey(v);
										break;
									case "bindevents":
										utils.each(v, function(fn, eventName) {
											editor.addListener(eventName, fn)
										});
										break;
									case "bindmultievents":
										utils.each(utils.isArray(v) ? v : [v], function(
											event) {
											var types = utils.trim(event.type)
												.split(/\s+/);
											utils.each(types, function(eventName) {
												editor.addListener(
													eventName, event
													.handler)
											})
										});
										break;
									case "commands":
										utils.each(v, function(execFn, execName) {
											editor.commands[execName] = execFn
										});
										break;
									case "outputrule":
										editor.addOutputRule(v);
										break;
									case "inputrule":
										editor.addInputRule(v);
										break;
									case "defaultoptions":
										editor.setOpt(v)
								}
							})
						}
					} else if (plugin.afterDisabled) {
						plugin.afterDisabled.call(editor)
					}
				});
				utils.each(UE.plugins, function(plugin) {
					plugin.call(editor)
				})
			},
			run: function(pluginName, editor) {
				var plugin = _plugins[pluginName];
				if (plugin) {
					plugin.exeFn.call(editor)
				}
			}
		}
	}();
	var keymap = UE.keymap = {
		Backspace: 8,
		Tab: 9,
		Enter: 13,
		Shift: 16,
		Control: 17,
		Alt: 18,
		CapsLock: 20,
		Esc: 27,
		Spacebar: 32,
		PageUp: 33,
		PageDown: 34,
		End: 35,
		Home: 36,
		Left: 37,
		Up: 38,
		Right: 39,
		Down: 40,
		Insert: 45,
		Del: 46,
		NumLock: 144,
		Cmd: 91,
		"=": 187,
		"-": 189,
		b: 66,
		i: 73,
		z: 90,
		y: 89,
		v: 86,
		x: 88,
		s: 83,
		n: 78
	};
	var LocalStorage = UE.LocalStorage = function() {
		var storage = window.localStorage;
		return {
			saveLocalData: function(key, data) {
				if (!storage) {
					return false
				}
				storage.setItem(key, data);
				return true
			},
			getLocalData: function(key) {
				if (!storage) {
					return null
				}
				return storage.getItem(key) || null
			},
			removeItem: function(key) {
				storage && storage.removeItem(key)
			}
		}
	}();
	(function() {
		var ROOT_KEY = "UEditorPlusPref";
		UE.Editor.prototype.setPreferences = function(key, value) {
			var obj = {};
			if (utils.isString(key)) {
				obj[key] = value
			} else {
				obj = key
			}
			var data = LocalStorage.getLocalData(ROOT_KEY);
			if (data && (data = utils.str2json(data))) {
				utils.extend(data, obj)
			} else {
				data = obj
			}
			data && LocalStorage.saveLocalData(ROOT_KEY, utils.json2str(data))
		};
		UE.Editor.prototype.getPreferences = function(key) {
			var data = LocalStorage.getLocalData(ROOT_KEY);
			if (data && (data = utils.str2json(data))) {
				return key ? data[key] : data
			}
			return null
		};
		UE.Editor.prototype.removePreferences = function(key) {
			var data = LocalStorage.getLocalData(ROOT_KEY);
			if (data && (data = utils.str2json(data))) {
				data[key] = undefined;
				delete data[key]
			}
			data && LocalStorage.saveLocalData(ROOT_KEY, utils.json2str(data))
		}
	})();
	UE.plugins["defaultfilter"] = function() {
		var me = this;
		me.setOpt({
			allowDivTransToP: true,
			disabledTableInTable: true,
			rgb2Hex: true
		});
		me.addInputRule(function(root) {
			var allowDivTransToP = this.options.allowDivTransToP;
			var val;

			function tdParent(node) {
				while (node && node.type == "element") {
					if (node.tagName == "td") {
						return true
					}
					node = node.parentNode
				}
				return false
			}
			root.traversal(function(node) {
				if (node.type == "element") {
					if (!dtd.$cdata[node.tagName] && me.options.autoClearEmptyNode && dtd
						.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs ||
							utils.isEmptyObject(node.attrs))) {
						if (!node.firstChild()) node.parentNode.removeChild(node);
						else if (node.tagName == "span" && (!node.attrs || utils.isEmptyObject(
								node.attrs))) {
							node.parentNode.removeChild(node, true)
						}
						return
					}
					switch (node.tagName) {
						case "style":
						case "script":
							node.setAttr({
								cdata_tag: node.tagName,
								cdata_data: node.innerHTML() || "",
								_ue_custom_node_: "true"
							});
							node.tagName = "div";
							node.innerHTML("");
							break;
						case "a":
							if (val = node.getAttr("href")) {
								node.setAttr("_href", val)
							}
							break;
						case "img":
							if (val = node.getAttr("src")) {
								if (/^data:/.test(val)) {
									node.parentNode.removeChild(node);
									break
								}
							}
							node.setAttr("_src", node.getAttr("src"));
							break;
						case "span":
							if (browser.webkit && (val = node.getStyle("white-space"))) {
								if (/nowrap|normal/.test(val)) {
									node.setStyle("white-space", "");
									if (me.options.autoClearEmptyNode && utils.isEmptyObject(
											node.attrs)) {
										node.parentNode.removeChild(node, true)
									}
								}
							}
							val = node.getAttr("id");
							if (val && /^_baidu_bookmark_/i.test(val)) {
								node.parentNode.removeChild(node)
							}
							break;
						case "p":
							if (val = node.getAttr("align")) {
								node.setAttr("align");
								node.setStyle("text-align", val)
							}
							utils.each(node.children, function(n) {
								if (n.type == "element" && n.tagName == "p") {
									var next = n.nextSibling();
									node.parentNode.insertAfter(n, node);
									var last = n;
									while (next) {
										var tmp = next.nextSibling();
										node.parentNode.insertAfter(next, last);
										last = next;
										next = tmp
									}
									return false
								}
							});
							if (!node.firstChild()) {
								node.innerHTML(browser.ie ? "&nbsp;" : "<br/>")
							}
							break;
						case "div":
							if (node.getAttr("cdata_tag")) {
								break
							}
							val = node.getAttr("class");
							if (val && /^line number\d+/.test(val)) {
								break
							}
							if (!allowDivTransToP) {
								break
							}
							var tmpNode, p = UE.uNode.createElement("p");
							while (tmpNode = node.firstChild()) {
								if (tmpNode.type == "text" || !UE.dom.dtd.$block[tmpNode
										.tagName]) {
									p.appendChild(tmpNode)
								} else {
									if (p.firstChild()) {
										node.parentNode.insertBefore(p, node);
										p = UE.uNode.createElement("p")
									} else {
										node.parentNode.insertBefore(tmpNode, node)
									}
								}
							}
							if (p.firstChild()) {
								node.parentNode.insertBefore(p, node)
							}
							node.parentNode.removeChild(node);
							break;
						case "dl":
							node.tagName = "ul";
							break;
						case "dt":
						case "dd":
							node.tagName = "li";
							break;
						case "li":
							var className = node.getAttr("class");
							if (!className || !/list\-/.test(className)) {
								node.setAttr()
							}
							var tmpNodes = node.getNodesByTagName("ol ul");
							UE.utils.each(tmpNodes, function(n) {
								node.parentNode.insertAfter(n, node)
							});
							break;
						case "td":
						case "th":
						case "caption":
							if (!node.children || !node.children.length) {
								node.appendChild(browser.ie11below ? UE.uNode.createText(" ") :
									UE.uNode.createElement("br"))
							}
							break;
						case "table":
							if (me.options.disabledTableInTable && tdParent(node)) {
								node.parentNode.insertBefore(UE.uNode.createText(node
								.innerText()), node);
								node.parentNode.removeChild(node)
							}
					}
				}
			})
		});
		me.addOutputRule(function(root) {
			var val;
			root.traversal(function(node) {
				if (node.type == "element") {
					if (me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd
						.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node
							.attrs))) {
						if (!node.firstChild()) node.parentNode.removeChild(node);
						else if (node.tagName == "span" && (!node.attrs || utils.isEmptyObject(
								node.attrs))) {
							node.parentNode.removeChild(node, true)
						}
						return
					}
					switch (node.tagName) {
						case "div":
							if (val = node.getAttr("cdata_tag")) {
								node.tagName = val;
								node.appendChild(UE.uNode.createText(node.getAttr(
									"cdata_data")));
								node.setAttr({
									cdata_tag: "",
									cdata_data: "",
									_ue_custom_node_: ""
								})
							}
							break;
						case "a":
							if (val = node.getAttr("_href")) {
								node.setAttr({
									href: utils.html(val),
									_href: ""
								})
							}
							break;
							break;
						case "span":
							val = node.getAttr("id");
							if (val && /^_baidu_bookmark_/i.test(val)) {
								node.parentNode.removeChild(node)
							}
							if (me.getOpt("rgb2Hex")) {
								var cssStyle = node.getAttr("style");
								if (cssStyle) {
									node.setAttr("style", cssStyle.replace(
										/rgba?\(([\d,\s]+)\)/g,
										function(a, value) {
											var array = value.split(",");
											if (array.length > 3) return "";
											value = "#";
											for (var i = 0, color; color = array[
												i++];) {
												color = parseInt(color.replace(
													/[^\d]/gi, ""), 10).toString(16);
												value += color.length == 1 ? "0" +
													color : color
											}
											return value.toUpperCase()
										}))
								}
							}
							break;
						case "img":
							if (val = node.getAttr("_src")) {
								node.setAttr({
									src: node.getAttr("_src"),
									_src: ""
								})
							}
					}
				}
			})
		})
	};
	UE.commands["inserthtml"] = {
		execCommand: function(command, html, notNeedFilter) {
			var me = this,
				range, div;
			if (!html) {
				return
			}
			if (me.fireEvent("beforeinserthtml", html) === true) {
				return
			}
			range = me.selection.getRange();
			div = range.document.createElement("div");
			div.style.display = "inline";
			if (!notNeedFilter) {
				var root = UE.htmlparser(html);
				if (me.options.filterRules) {
					UE.filterNode(root, me.options.filterRules)
				}
				me.filterInputRule(root);
				html = root.toHtml()
			}
			div.innerHTML = utils.trim(html);
			if (!range.collapsed) {
				var tmpNode = range.startContainer;
				if (domUtils.isFillChar(tmpNode)) {
					range.setStartBefore(tmpNode)
				}
				tmpNode = range.endContainer;
				if (domUtils.isFillChar(tmpNode)) {
					range.setEndAfter(tmpNode)
				}
				range.txtToElmBoundary();
				if (range.endContainer && range.endContainer.nodeType == 1) {
					tmpNode = range.endContainer.childNodes[range.endOffset];
					if (tmpNode && domUtils.isBr(tmpNode)) {
						range.setEndAfter(tmpNode)
					}
				}
				if (range.startOffset == 0) {
					tmpNode = range.startContainer;
					if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
						tmpNode = range.endContainer;
						if (range.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode
								.childNodes.length) && domUtils.isBoundaryNode(tmpNode, "lastChild")) {
							me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
							range.setStart(me.body.firstChild, 0).collapse(true)
						}
					}
				}!range.collapsed && range.deleteContents();
				if (range.startContainer.nodeType == 1) {
					var child = range.startContainer.childNodes[range.startOffset],
						pre;
					if (child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils
						.isBlockElm(pre)) {
						range.setEnd(pre, pre.childNodes.length).collapse();
						while (child.firstChild) {
							pre.appendChild(child.firstChild)
						}
						domUtils.remove(child)
					}
				}
			}
			var child, parent, pre, tmp, hadBreak = 0,
				nextNode;
			if (range.inFillChar()) {
				child = range.startContainer;
				if (domUtils.isFillChar(child)) {
					range.setStartBefore(child).collapse(true);
					domUtils.remove(child)
				} else if (domUtils.isFillChar(child, true)) {
					child.nodeValue = child.nodeValue.replace(fillCharReg, "");
					range.startOffset--;
					range.collapsed && range.collapse(true)
				}
			}
			var li = domUtils.findParentByTagName(range.startContainer, "li", true);
			if (li) {
				var next, last;
				while (child = div.firstChild) {
					while (child && (child.nodeType == 3 || !domUtils.isBlockElm(child) || child.tagName ==
							"HR")) {
						next = child.nextSibling;
						range.insertNode(child).collapse();
						last = child;
						child = next
					}
					if (child) {
						if (/^(ol|ul)$/i.test(child.tagName)) {
							while (child.firstChild) {
								last = child.firstChild;
								domUtils.insertAfter(li, child.firstChild);
								li = li.nextSibling
							}
							domUtils.remove(child)
						} else {
							var tmpLi;
							next = child.nextSibling;
							tmpLi = me.document.createElement("li");
							domUtils.insertAfter(li, tmpLi);
							tmpLi.appendChild(child);
							last = child;
							child = next;
							li = tmpLi
						}
					}
				}
				li = domUtils.findParentByTagName(range.startContainer, "li", true);
				if (domUtils.isEmptyBlock(li)) {
					domUtils.remove(li)
				}
				if (last) {
					range.setStartAfter(last).collapse(true).select(true)
				}
			} else {
				while (child = div.firstChild) {
					if (hadBreak) {
						var p = me.document.createElement("p");
						while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
							nextNode = child.nextSibling;
							p.appendChild(child);
							child = nextNode
						}
						if (p.firstChild) {
							child = p
						}
					}
					range.insertNode(child);
					nextNode = child.nextSibling;
					if (!hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm(
						child)) {
						parent = domUtils.findParent(child, function(node) {
							return domUtils.isBlockElm(node)
						});
						if (parent && parent.tagName.toLowerCase() != "body" && !(dtd[parent.tagName][child
								.nodeName
							] && child.parentNode === parent)) {
							if (!dtd[parent.tagName][child.nodeName]) {
								pre = parent
							} else {
								tmp = child.parentNode;
								while (tmp !== parent) {
									pre = tmp;
									tmp = tmp.parentNode
								}
							}
							domUtils.breakParent(child, pre || tmp);
							var pre = child.previousSibling;
							domUtils.trimWhiteTextNode(pre);
							if (!pre.childNodes.length) {
								domUtils.remove(pre)
							}
							if (!browser.ie && (next = child.nextSibling) && domUtils.isBlockElm(next) &&
								next.lastChild && !domUtils.isBr(next.lastChild)) {
								next.appendChild(me.document.createElement("br"))
							}
							hadBreak = 1
						}
					}
					var next = child.nextSibling;
					if (!div.firstChild && next && domUtils.isBlockElm(next)) {
						range.setStart(next, 0).collapse(true);
						break
					}
					range.setEndAfter(child).collapse()
				}
				child = range.startContainer;
				if (nextNode && domUtils.isBr(nextNode)) {
					domUtils.remove(nextNode)
				}
				if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
					if (nextNode = child.nextSibling) {
						domUtils.remove(child);
						if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
							range.setStart(nextNode, 0).collapse(true).shrinkBoundary()
						}
					} else {
						try {
							child.innerHTML = browser.ie ? domUtils.fillChar : "<br/>"
						} catch (e) {
							range.setStartBefore(child);
							domUtils.remove(child)
						}
					}
				}
				try {
					range.select(true)
				} catch (e) {}
			}
			setTimeout(function() {
				range = me.selection.getRange();
				range.scrollToView(me.autoHeightEnabled, me.autoHeightEnabled ? domUtils.getXY(me
					.iframe).y : 0);
				me.fireEvent("afterinserthtml", html)
			}, 200)
		}
	};
	UE.plugins["autotypeset"] = function() {
		this.setOpt({
			autotypeset: {
				mergeEmptyline: true,
				removeClass: true,
				removeEmptyline: false,
				textAlign: "left",
				imageBlockLine: "center",
				pasteFilter: false,
				clearFontSize: false,
				clearFontFamily: false,
				removeEmptyNode: false,
				removeTagNames: utils.extend({
					div: 1
				}, dtd.$removeEmpty),
				indent: false,
				indentValue: "2em",
				bdc2sb: false,
				tobdc: false
			}
		});
		var me = this,
			opt = me.options.autotypeset,
			remainClass = {
				selectTdClass: 1,
				pagebreak: 1,
				anchorclass: 1
			},
			remainTag = {
				li: 1
			},
			tags = {
				div: 1,
				p: 1,
				blockquote: 1,
				center: 1,
				h1: 1,
				h2: 1,
				h3: 1,
				h4: 1,
				h5: 1,
				h6: 1,
				span: 1
			},
			highlightCont;
		if (!opt) {
			return
		}
		readLocalOpts();

		function isLine(node, notEmpty) {
			if (!node || node.nodeType == 3) return 0;
			if (domUtils.isBr(node)) return 1;
			if (node && node.parentNode && tags[node.tagName.toLowerCase()]) {
				if (highlightCont && highlightCont.contains(node) || node.getAttribute("pagebreak")) {
					return 0
				}
				return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node, new RegExp("[\\s" +
					domUtils.fillChar + "]", "g"))
			}
		}

		function removeNotAttributeSpan(node) {
			if (!node.style.cssText) {
				domUtils.removeAttributes(node, ["style"]);
				if (node.tagName.toLowerCase() == "span" && domUtils.hasNoAttributes(node)) {
					domUtils.remove(node, true)
				}
			}
		}

		function autotype(type, html) {
			var me = this,
				cont;
			if (html) {
				if (!opt.pasteFilter) {
					return
				}
				cont = me.document.createElement("div");
				cont.innerHTML = html.html
			} else {
				cont = me.document.body
			}
			var nodes = domUtils.getElementsByTagName(cont, "*");
			for (var i = 0, ci; ci = nodes[i++];) {
				if (me.fireEvent("excludeNodeinautotype", ci) === true) {
					continue
				}
				if (opt.clearFontSize && ci.style.fontSize) {
					domUtils.removeStyle(ci, "font-size");
					removeNotAttributeSpan(ci)
				}
				if (opt.clearFontFamily && ci.style.fontFamily) {
					domUtils.removeStyle(ci, "font-family");
					removeNotAttributeSpan(ci)
				}
				if (isLine(ci)) {
					if (opt.mergeEmptyline) {
						var next = ci.nextSibling,
							tmpNode, isBr = domUtils.isBr(ci);
						while (isLine(next)) {
							tmpNode = next;
							next = tmpNode.nextSibling;
							if (isBr && (!next || next && !domUtils.isBr(next))) {
								break
							}
							domUtils.remove(tmpNode)
						}
					}
					if (opt.removeEmptyline && domUtils.inDoc(ci, cont) && !remainTag[ci.parentNode.tagName
							.toLowerCase()]) {
						if (domUtils.isBr(ci)) {
							next = ci.nextSibling;
							if (next && !domUtils.isBr(next)) {
								continue
							}
						}
						domUtils.remove(ci);
						continue
					}
				}
				if (isLine(ci, true) && ci.tagName != "SPAN") {
					if (opt.indent) {
						ci.style.textIndent = opt.indentValue
					}
					if (opt.textAlign) {
						ci.style.textAlign = opt.textAlign
					}
				}
				if (opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]) {
					if (highlightCont && highlightCont.contains(ci)) {
						continue
					}
					domUtils.removeAttributes(ci, ["class"])
				}
				if (opt.imageBlockLine && ci.tagName.toLowerCase() == "img" && !ci.getAttribute("emotion")) {
					if (html) {
						var img = ci;
						switch (opt.imageBlockLine) {
							case "left":
							case "right":
							case "none":
								var pN = img.parentNode,
									tmpNode, pre, next;
								while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
									pN = pN.parentNode
								}
								tmpNode = pN;
								if (tmpNode.tagName == "P" && domUtils.getStyle(tmpNode, "text-align") ==
									"center") {
									if (!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function(
											node) {
											return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
										}) == 1) {
										pre = tmpNode.previousSibling;
										next = tmpNode.nextSibling;
										if (pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre
											.tagName == next.tagName && domUtils.isBlockElm(pre)) {
											pre.appendChild(tmpNode.firstChild);
											while (next.firstChild) {
												pre.appendChild(next.firstChild)
											}
											domUtils.remove(tmpNode);
											domUtils.remove(next)
										} else {
											domUtils.setStyle(tmpNode, "text-align", "")
										}
									}
								}
								domUtils.setStyle(img, "float", opt.imageBlockLine);
								break;
							case "center":
								if (me.queryCommandValue("imagefloat") != "center") {
									pN = img.parentNode;
									domUtils.setStyle(img, "float", "none");
									tmpNode = img;
									while (pN && domUtils.getChildCount(pN, function(node) {
											return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
										}) == 1 && (dtd.$inline[pN.tagName] || pN.tagName == "A")) {
										tmpNode = pN;
										pN = pN.parentNode
									}
									var pNode = me.document.createElement("p");
									domUtils.setAttributes(pNode, {
										style: "text-align:center"
									});
									tmpNode.parentNode.insertBefore(pNode, tmpNode);
									pNode.appendChild(tmpNode);
									domUtils.setStyle(tmpNode, "float", "")
								}
						}
					} else {
						var range = me.selection.getRange();
						range.selectNode(ci).select();
						me.execCommand("imagefloat", opt.imageBlockLine)
					}
				}
				if (opt.removeEmptyNode) {
					if (opt.removeTagNames[ci.tagName.toLowerCase()] && domUtils.hasNoAttributes(ci) && domUtils
						.isEmptyBlock(ci)) {
						domUtils.remove(ci)
					}
				}
			}
			if (opt.tobdc) {
				var root = UE.htmlparser(cont.innerHTML);
				root.traversal(function(node) {
					if (node.type == "text") {
						node.data = ToDBC(node.data)
					}
				});
				cont.innerHTML = root.toHtml()
			}
			if (opt.bdc2sb) {
				var root = UE.htmlparser(cont.innerHTML);
				root.traversal(function(node) {
					if (node.type == "text") {
						node.data = DBC2SB(node.data)
					}
				});
				cont.innerHTML = root.toHtml()
			}
			if (html) {
				html.html = cont.innerHTML
			}
		}
		if (opt.pasteFilter) {
			me.addListener("beforepaste", autotype)
		}

		function DBC2SB(str) {
			var result = "";
			for (var i = 0; i < str.length; i++) {
				var code = str.charCodeAt(i);
				if (code >= 65281 && code <= 65373) {
					result += String.fromCharCode(str.charCodeAt(i) - 65248)
				} else if (code == 12288) {
					result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32)
				} else {
					result += str.charAt(i)
				}
			}
			return result
		}

		function ToDBC(txtstring) {
			txtstring = utils.html(txtstring);
			var tmp = "";
			var mark = "";
			for (var i = 0; i < txtstring.length; i++) {
				if (txtstring.charCodeAt(i) == 32) {
					tmp = tmp + String.fromCharCode(12288)
				} else if (txtstring.charCodeAt(i) < 127) {
					tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248)
				} else {
					tmp += txtstring.charAt(i)
				}
			}
			return tmp
		}

		function readLocalOpts() {
			var cookieOpt = me.getPreferences("autotypeset");
			utils.extend(me.options.autotypeset, cookieOpt)
		}
		me.commands["autotypeset"] = {
			execCommand: function() {
				me.removeListener("beforepaste", autotype);
				if (opt.pasteFilter) {
					me.addListener("beforepaste", autotype)
				}
				autotype.call(me)
			}
		}
	};
	UE.plugin.register("autosubmit", function() {
		return {
			shortcutkey: {
				autosubmit: "ctrl+13"
			},
			commands: {
				autosubmit: {
					execCommand: function() {
						var me = this,
							form = domUtils.findParentByTagName(me.iframe, "form", false);
						if (form) {
							if (me.fireEvent("beforesubmit") === false) {
								return
							}
							me.sync();
							form.submit()
						}
					}
				}
			}
		}
	});
	UE.plugin.register("background", function() {
		var me = this,
			cssRuleId = "editor_background",
			isSetColored, reg = new RegExp("body[\\s]*\\{(.+)\\}", "i");

		function stringToObj(str) {
			var obj = {},
				styles = str.split(";");
			utils.each(styles, function(v) {
				var index = v.indexOf(":"),
					key = utils.trim(v.substr(0, index)).toLowerCase();
				key && (obj[key] = utils.trim(v.substr(index + 1) || ""))
			});
			return obj
		}

		function setBackground(obj) {
			if (obj) {
				var styles = [];
				for (var name in obj) {
					if (obj.hasOwnProperty(name)) {
						styles.push(name + ":" + obj[name] + "; ")
					}
				}
				utils.cssRule(cssRuleId, styles.length ? "body{" + styles.join("") + "}" : "", me.document)
			} else {
				utils.cssRule(cssRuleId, "", me.document)
			}
		}
		var orgFn = me.hasContents;
		me.hasContents = function() {
			if (me.queryCommandValue("background")) {
				return true
			}
			return orgFn.apply(me, arguments)
		};
		return {
			bindEvents: {
				getAllHtml: function(type, headHtml) {
					var body = this.body,
						su = domUtils.getComputedStyle(body, "background-image"),
						url = "";
					if (su.indexOf(me.options.imagePath) > 0) {
						url = su.substring(su.indexOf(me.options.imagePath), su.length - 1).replace(
							/"|\(|\)/gi, "")
					} else {
						url = su != "none" ? su.replace(/url\("?|"?\)/gi, "") : ""
					}
					var html = '<style type="text/css">body{';
					var bgObj = {
						"background-color": domUtils.getComputedStyle(body, "background-color") ||
							"#ffffff",
						"background-image": url ? "url(" + url + ")" : "",
						"background-repeat": domUtils.getComputedStyle(body, "background-repeat") ||
							"",
						"background-position": browser.ie ? domUtils.getComputedStyle(body,
							"background-position-x") + " " + domUtils.getComputedStyle(body,
							"background-position-y") : domUtils.getComputedStyle(body,
							"background-position"),
						height: domUtils.getComputedStyle(body, "height")
					};
					for (var name in bgObj) {
						if (bgObj.hasOwnProperty(name)) {
							html += name + ":" + bgObj[name] + "; "
						}
					}
					html += "}</style> ";
					headHtml.push(html)
				},
				aftersetcontent: function() {
					if (isSetColored == false) setBackground()
				}
			},
			inputRule: function(root) {
				isSetColored = false;
				utils.each(root.getNodesByTagName("p"), function(p) {
					var styles = p.getAttr("data-background");
					if (styles) {
						isSetColored = true;
						setBackground(stringToObj(styles));
						p.parentNode.removeChild(p)
					}
				})
			},
			outputRule: function(root) {
				var me = this,
					styles = (utils.cssRule(cssRuleId, me.document) || "").replace(/[\n\r]+/g, "")
					.match(reg);
				if (styles) {
					root.appendChild(UE.uNode.createElement(
						'<p style="display:none;" data-background="' + utils.trim(styles[1]
							.replace(/"/g, "").replace(/[\s]+/g, " ")) + '"><br/></p>'))
				}
			},
			commands: {
				background: {
					execCommand: function(cmd, obj) {
						setBackground(obj)
					},
					queryCommandValue: function() {
						var me = this,
							styles = (utils.cssRule(cssRuleId, me.document) || "").replace(/[\n\r]+/g,
								"").match(reg);
						return styles ? stringToObj(styles[1]) : null
					},
					notNeedUndo: true
				}
			}
		}
	});
	UE.commands["imagefloat"] = {
		execCommand: function(cmd, align) {
			var me = this,
				range = me.selection.getRange();
			if (!range.collapsed) {
				var img = range.getClosedNode();
				if (img && img.tagName === "IMG") {
					switch (align) {
						case "left":
						case "right":
						case "none":
							var pN = img.parentNode,
								tmpNode, pre, next;
							while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
								pN = pN.parentNode
							}
							tmpNode = pN;
							if (tmpNode.tagName == "P" && domUtils.getStyle(tmpNode, "text-align") ==
								"center") {
								if (!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function(
										node) {
										return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
									}) == 1) {
									pre = tmpNode.previousSibling;
									next = tmpNode.nextSibling;
									if (pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre
										.tagName == next.tagName && domUtils.isBlockElm(pre)) {
										pre.appendChild(tmpNode.firstChild);
										while (next.firstChild) {
											pre.appendChild(next.firstChild)
										}
										domUtils.remove(tmpNode);
										domUtils.remove(next)
									} else {
										domUtils.setStyle(tmpNode, "text-align", "")
									}
								}
								range.selectNode(img).select()
							}
							domUtils.setStyle(img, "float", align == "none" ? "" : align);
							if (align == "none") {
								domUtils.removeAttributes(img, "align")
							}
							break;
						case "center":
							if (me.queryCommandValue("imagefloat") != "center") {
								pN = img.parentNode;
								domUtils.setStyle(img, "float", "");
								domUtils.removeAttributes(img, "align");
								tmpNode = img;
								while (pN && domUtils.getChildCount(pN, function(node) {
										return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
									}) == 1 && (dtd.$inline[pN.tagName] || pN.tagName == "A")) {
									tmpNode = pN;
									pN = pN.parentNode
								}
								range.setStartBefore(tmpNode).setCursor(false);
								pN = me.document.createElement("div");
								pN.appendChild(tmpNode);
								domUtils.setStyle(tmpNode, "float", "");
								me.execCommand("insertHtml",
									'<p id="_img_parent_tmp" style="text-align:center">' + pN
									.innerHTML + "</p>");
								tmpNode = me.document.getElementById("_img_parent_tmp");
								tmpNode.removeAttribute("id");
								tmpNode = tmpNode.firstChild;
								range.selectNode(tmpNode).select();
								next = tmpNode.parentNode.nextSibling;
								if (next && domUtils.isEmptyNode(next)) {
									domUtils.remove(next)
								}
							}
							break
					}
				}
			}
		},
		queryCommandValue: function() {
			var range = this.selection.getRange(),
				startNode, floatStyle;
			if (range.collapsed) {
				return "none"
			}
			startNode = range.getClosedNode();
			if (startNode && startNode.nodeType == 1 && startNode.tagName == "IMG") {
				floatStyle = domUtils.getComputedStyle(startNode, "float") || startNode.getAttribute(
					"align");
				if (floatStyle == "none") {
					floatStyle = domUtils.getComputedStyle(startNode.parentNode, "text-align") == "center" ?
						"center" : floatStyle
				}
				return {
					left: 1,
					right: 1,
					center: 1
				} [floatStyle] ? floatStyle: "none"
			}
			return "none"
		},
		queryCommandState: function() {
			var range = this.selection.getRange(),
				startNode;
			if (range.collapsed) return -1;
			startNode = range.getClosedNode();
			if (startNode && startNode.nodeType === 1 && startNode.tagName === "IMG") {
				return 0
			}
			return -1
		}
	};
	UE.commands["insertimage"] = {
		execCommand: function(cmd, opt) {
			opt = utils.isArray(opt) ? opt : [opt];
			if (!opt.length) {
				return
			}
			var me = this,
				range = me.selection.getRange(),
				img = range.getClosedNode();
			if (me.fireEvent("beforeinsertimage", opt) === true) {
				return
			}
			if (img && /img/i.test(img.tagName) && (img.className != "edui-faked-video" || img.className
					.indexOf("edui-upload-video") != -1) && !img.getAttribute("data-word-image")) {
				var first = opt.shift();
				var floatStyle = first["floatStyle"];
				delete first["floatStyle"];
				domUtils.setAttributes(img, first);
				me.execCommand("imagefloat", floatStyle);
				if (opt.length > 0) {
					range.setStartAfter(img).setCursor(false, true);
					me.execCommand("insertimage", opt)
				}
			} else {
				var html = [],
					str = "",
					ci;
				ci = opt[0];
				if (opt.length == 1) {
					str = '<img src="' + ci.src + '" ' + (ci._src ? ' _src="' + ci._src + '" ' : "") + (ci
						.width ? 'width="' + ci.width + '" ' : "") + (ci.height ? ' height="' + ci
						.height + '" ' : "") + (ci["floatStyle"] == "left" || ci["floatStyle"] ==
						"right" ? ' style="float:' + ci["floatStyle"] + ';"' : "") + (ci.title && ci
						.title != "" ? ' title="' + ci.title + '"' : "") + (ci.border && ci.border !=
						"0" ? ' border="' + ci.border + '"' : "") + (ci.alt && ci.alt != "" ? ' alt="' +
						ci.alt + '"' : "") + (ci.hspace && ci.hspace != "0" ? ' hspace = "' + ci
						.hspace + '"' : "") + (ci.vspace && ci.vspace != "0" ? ' vspace = "' + ci
						.vspace + '"' : "") + "/>";
					if (ci["floatStyle"] == "center") {
						str = '<p style="text-align: center">' + str + "</p>"
					}
					html.push(str)
				} else {
					for (var i = 0; ci = opt[i++];) {
						str = "<p " + (ci["floatStyle"] == "center" ? 'style="text-align: center" ' : "") +
							'><img src="' + ci.src + '" ' + (ci.width ? 'width="' + ci.width + '" ' : "") +
							(ci._src ? ' _src="' + ci._src + '" ' : "") + (ci.height ? ' height="' + ci
								.height + '" ' : "") + ' style="' + (ci["floatStyle"] && ci["floatStyle"] !=
								"center" ? "float:" + ci["floatStyle"] + ";" : "") + (ci.border || "") +
							'" ' + (ci.title ? ' title="' + ci.title + '"' : "") + " /></p>";
						html.push(str)
					}
				}
				me.execCommand("insertHtml", html.join(""))
			}
			me.fireEvent("afterinsertimage", opt)
		}
	};
	UE.plugins["justify"] = function() {
		var me = this,
			block = domUtils.isBlockElm,
			defaultValue = {
				left: 1,
				right: 1,
				center: 1,
				justify: 1
			},
			doJustify = function(range, style) {
				var bookmark = range.createBookmark(),
					filterFn = function(node) {
						return node.nodeType == 1 ? node.tagName.toLowerCase() != "br" && !domUtils
							.isBookmarkNode(node) : !domUtils.isWhitespace(node)
					};
				range.enlarge(true);
				var bookmark2 = range.createBookmark(),
					current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
					tmpRange = range.cloneRange(),
					tmpNode;
				while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils
					.POSITION_FOLLOWING)) {
					if (current.nodeType == 3 || !block(current)) {
						tmpRange.setStartBefore(current);
						while (current && current !== bookmark2.end && !block(current)) {
							tmpNode = current;
							current = domUtils.getNextDomNode(current, false, null, function(node) {
								return !block(node)
							})
						}
						tmpRange.setEndAfter(tmpNode);
						var common = tmpRange.getCommonAncestor();
						if (!domUtils.isBody(common) && block(common)) {
							domUtils.setStyles(common, utils.isString(style) ? {
								"text-align": style
							} : style);
							current = common
						} else {
							var p = range.document.createElement("p");
							domUtils.setStyles(p, utils.isString(style) ? {
								"text-align": style
							} : style);
							var frag = tmpRange.extractContents();
							p.appendChild(frag);
							tmpRange.insertNode(p);
							current = p
						}
						current = domUtils.getNextDomNode(current, false, filterFn)
					} else {
						current = domUtils.getNextDomNode(current, true, filterFn)
					}
				}
				return range.moveToBookmark(bookmark2).moveToBookmark(bookmark)
			};
		UE.commands["justify"] = {
			execCommand: function(cmdName, align) {
				var range = this.selection.getRange(),
					txt;
				if (range.collapsed) {
					txt = this.document.createTextNode("p");
					range.insertNode(txt)
				}
				doJustify(range, align);
				if (txt) {
					range.setStartBefore(txt).collapse(true);
					domUtils.remove(txt)
				}
				range.select();
				return true
			},
			queryCommandValue: function() {
				var startNode = this.selection.getStart(),
					value = domUtils.getComputedStyle(startNode, "text-align");
				return defaultValue[value] ? value : "left"
			},
			queryCommandState: function() {
				var start = this.selection.getStart(),
					cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
				return cell ? -1 : 0
			}
		}
	};
	UE.plugins["font"] = function() {
		var me = this,
			fonts = {
				forecolor: "color",
				backcolor: "background-color",
				fontsize: "font-size",
				fontfamily: "font-family",
				underline: "text-decoration",
				strikethrough: "text-decoration",
				fontborder: "border"
			},
			lang = me.getLang(),
			needCmd = {
				underline: 1,
				strikethrough: 1,
				fontborder: 1
			},
			needSetChild = {
				forecolor: "color",
				backcolor: "background-color",
				fontsize: "font-size",
				fontfamily: "font-family"
			};
		me.setOpt({
			fontfamily: [{
				name: "default",
				val: "default"
			}, {
				name: "songti",
				val: "宋体,SimSun"
			}, {
				name: "yahei",
				val: "微软雅黑,Microsoft YaHei"
			}, {
				name: "kaiti",
				val: "楷体,楷体_GB2312,SimKai"
			}, {
				name: "heiti",
				val: "黑体,SimHei"
			}, {
				name: "lishu",
				val: "隶书,SimLi"
			}, {
				name: "arial",
				val: "arial,helvetica,sans-serif"
			}, {
				name: "timesNewRoman",
				val: "times new roman"
			}],
			fontsize: [10, 11, 12, 14, 16, 18, 20, 24, 36]
		});

		function mergeWithParent(node) {
			var parent;
			while (parent = node.parentNode) {
				if (parent.tagName == "SPAN" && domUtils.getChildCount(parent, function(child) {
						return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child)
					}) == 1) {
					parent.style.cssText += node.style.cssText;
					domUtils.remove(node, true);
					node = parent
				} else {
					break
				}
			}
		}

		function mergeChild(rng, cmdName, value) {
			if (needSetChild[cmdName]) {
				rng.adjustmentBoundary();
				if (!rng.collapsed && rng.startContainer.nodeType == 1) {
					var start = rng.startContainer.childNodes[rng.startOffset];
					if (start && domUtils.isTagNode(start, "span")) {
						var bk = rng.createBookmark();
						utils.each(domUtils.getElementsByTagName(start, "span"), function(span) {
							if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
							if (cmdName == "backcolor" && domUtils.getComputedStyle(span,
									"background-color").toLowerCase() === value) {
								return
							}
							domUtils.removeStyle(span, needSetChild[cmdName]);
							if (span.style.cssText.replace(/^\s+$/, "").length == 0) {
								domUtils.remove(span, true)
							}
						});
						rng.moveToBookmark(bk)
					}
				}
			}
		}

		function mergesibling(rng, cmdName, value) {
			var collapsed = rng.collapsed,
				bk = rng.createBookmark(),
				common;
			if (collapsed) {
				common = bk.start.parentNode;
				while (dtd.$inline[common.tagName]) {
					common = common.parentNode
				}
			} else {
				common = domUtils.getCommonAncestor(bk.start, bk.end)
			}
			utils.each(domUtils.getElementsByTagName(common, "span"), function(span) {
				if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
				if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
					if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
						domUtils.remove(span, true)
					} else {
						domUtils.removeStyle(span, "border")
					}
					return
				}
				if (/border/i.test(span.style.cssText) && span.parentNode.tagName == "SPAN" && /border/i
					.test(span.parentNode.style.cssText)) {
					span.style.cssText = span.style.cssText.replace(/border[^:]*:[^;]+;?/gi, "")
				}
				if (!(cmdName == "fontborder" && value == "none")) {
					var next = span.nextSibling;
					while (next && next.nodeType == 1 && next.tagName == "SPAN") {
						if (domUtils.isBookmarkNode(next) && cmdName == "fontborder") {
							span.appendChild(next);
							next = span.nextSibling;
							continue
						}
						if (next.style.cssText == span.style.cssText) {
							domUtils.moveChild(next, span);
							domUtils.remove(next)
						}
						if (span.nextSibling === next) break;
						next = span.nextSibling
					}
				}
				mergeWithParent(span);
				if (browser.ie && browser.version > 8) {
					var parent = domUtils.findParent(span, function(n) {
						return n.tagName == "SPAN" && /background-color/.test(n.style.cssText)
					});
					if (parent && !/background-color/.test(span.style.cssText)) {
						span.style.backgroundColor = parent.style.backgroundColor
					}
				}
			});
			rng.moveToBookmark(bk);
			mergeChild(rng, cmdName, value)
		}
		me.addInputRule(function(root) {
			utils.each(root.getNodesByTagName("u s del font strike"), function(node) {
				if (node.tagName == "font") {
					var cssStyle = [];
					for (var p in node.attrs) {
						switch (p) {
							case "size":
								cssStyle.push("font-size:" + ({
									1: "10",
									2: "12",
									3: "16",
									4: "18",
									5: "24",
									6: "32",
									7: "48"
								} [node.attrs[p]] || node.attrs[p]) + "px");
								break;
							case "color":
								cssStyle.push("color:" + node.attrs[p]);
								break;
							case "face":
								cssStyle.push("font-family:" + node.attrs[p]);
								break;
							case "style":
								cssStyle.push(node.attrs[p])
						}
					}
					node.attrs = {
						style: cssStyle.join(";")
					}
				} else {
					var val = node.tagName == "u" ? "underline" : "line-through";
					node.attrs = {
						style: (node.getAttr("style") || "") + "text-decoration:" + val +
							";"
					}
				}
				node.tagName = "span"
			})
		});
		for (var p in fonts) {
			(function(cmd, style) {
				UE.commands[cmd] = {
					execCommand: function(cmdName, value) {
						value = value || (this.queryCommandState(cmdName) ? "none" : cmdName ===
							"underline" ? "underline" : cmdName === "fontborder" ?
							"1px solid #000" : "line-through");
						var me = this,
							range = this.selection.getRange(),
							text;
						if (value === "default") {
							if (range.collapsed) {
								text = me.document.createTextNode("font");
								range.insertNode(text).select()
							}
							me.execCommand("removeFormat", "span,a", style);
							if (text) {
								range.setStartBefore(text).collapse(true);
								domUtils.remove(text)
							}
							mergesibling(range, cmdName, value);
							range.select()
						} else {
							if (!range.collapsed) {
								if (needCmd[cmd] && me.queryCommandValue(cmd)) {
									me.execCommand("removeFormat", "span,a", style)
								}
								range = me.selection.getRange();
								range.applyInlineStyle("span", {
									style: style + ":" + value
								});
								mergesibling(range, cmdName, value);
								range.select()
							} else {
								var span = domUtils.findParentByTagName(range.startContainer,
									"span", true);
								text = me.document.createTextNode("font");
								if (span && !span.children.length && !span[browser.ie ?
										"innerText" : "textContent"].replace(fillCharReg, "")
									.length) {
									range.insertNode(text);
									if (needCmd[cmd]) {
										range.selectNode(text).select();
										me.execCommand("removeFormat", "span,a", style, null);
										span = domUtils.findParentByTagName(text, "span", true);
										range.setStartBefore(text)
									}
									span && (span.style.cssText += ";" + style + ":" + value);
									range.collapse(true).select()
								} else {
									range.insertNode(text);
									range.selectNode(text).select();
									span = range.document.createElement("span");
									if (needCmd[cmd]) {
										if (domUtils.findParentByTagName(text, "a", true)) {
											range.setStartBefore(text).setCursor();
											domUtils.remove(text);
											return
										}
										me.execCommand("removeFormat", "span,a", style)
									}
									span.style.cssText = style + ":" + value;
									text.parentNode.insertBefore(span, text);
									if (!browser.ie || browser.ie && browser.version === 9) {
										var spanParent = span.parentNode;
										while (!domUtils.isBlockElm(spanParent)) {
											if (spanParent.tagName === "SPAN") {
												span.style.cssText = spanParent.style.cssText +
													";" + span.style.cssText
											}
											spanParent = spanParent.parentNode
										}
									}
									if (opera) {
										setTimeout(function() {
											range.setStart(span, 0).collapse(true);
											mergesibling(range, cmdName, value);
											range.select()
										})
									} else {
										range.setStart(span, 0).collapse(true);
										mergesibling(range, cmdName, value);
										range.select()
									}
								}
								domUtils.remove(text)
							}
						}
						return true
					},
					queryCommandValue: function(cmdName) {
						var startNode = this.selection.getStart();
						var styleVal;
						if (cmdName === "underline" || cmdName === "strikethrough") {
							var tmpNode = startNode,
								value;
							while (tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(
									tmpNode)) {
								if (tmpNode.nodeType === 1) {
									value = domUtils.getComputedStyle(tmpNode, style);
									if (value !== "none") {
										return value
									}
								}
								tmpNode = tmpNode.parentNode
							}
							return "none"
						} else if (cmdName === "fontborder") {
							var tmp = startNode,
								val;
							while (tmp && dtd.$inline[tmp.tagName]) {
								if (val = domUtils.getComputedStyle(tmp, "border")) {
									if (/1px/.test(val) && /solid/.test(val)) {
										return val
									}
								}
								tmp = tmp.parentNode
							}
							return ""
						} else if (cmdName === "FontSize") {
							styleVal = domUtils.getComputedStyle(startNode, style);
							tmp = /^([\d\.]+)(\w+)$/.exec(styleVal);
							if (tmp) {
								return Math.floor(tmp[1]) + tmp[2]
							}
							return styleVal
						} else if (cmdName === "FontFamily") {
							styleVal = domUtils.getComputedStyle(startNode, style);
							styleVal = styleVal.replace(/['"]/g, "");
							styleVal = styleVal.replace(/\s*,\s*/g, ",");
							var fontFamily = lang.fontfamily.default;
							var fontList = me.options["fontfamily"] || [];
							for (var i = 0; i < fontList.length; i++) {
								var v = fontList[i];
								if (v.val === styleVal) {
									fontFamily = styleVal;
									break
								}
							}
							return fontFamily
						}
						value = domUtils.getComputedStyle(startNode, style);
						return value
					},
					queryCommandState: function(cmdName) {
						if (!needCmd[cmdName]) return 0;
						var val = this.queryCommandValue(cmdName);
						if (cmdName === "fontborder") {
							return /1px/.test(val) && /solid/.test(val)
						} else {
							return cmdName === "underline" ? /underline/.test(val) : /line\-through/
								.test(val)
						}
					}
				}
			})(p, fonts[p])
		}
	};
	UE.plugins["link"] = function() {
		function optimize(range) {
			var start = range.startContainer,
				end = range.endContainer;
			if (start = domUtils.findParentByTagName(start, "a", true)) {
				range.setStartBefore(start)
			}
			if (end = domUtils.findParentByTagName(end, "a", true)) {
				range.setEndAfter(end)
			}
		}
		UE.commands["unlink"] = {
			execCommand: function() {
				var range = this.selection.getRange(),
					bookmark;
				if (range.collapsed && !domUtils.findParentByTagName(range.startContainer, "a", true)) {
					return
				}
				bookmark = range.createBookmark();
				optimize(range);
				range.removeInlineStyle("a").moveToBookmark(bookmark).select()
			},
			queryCommandState: function() {
				return !this.highlight && this.queryCommandValue("link") ? 0 : -1
			}
		};

		function doLink(range, opt, me) {
			var rngClone = range.cloneRange(),
				link = me.queryCommandValue("link");
			optimize(range = range.adjustmentBoundary());
			var start = range.startContainer;
			if (start.nodeType == 1 && link) {
				start = start.childNodes[range.startOffset];
				if (start && start.nodeType == 1 && start.tagName == "A" && /^(?:https?|ftp|file)\s*:\s*\/\//
					.test(start[browser.ie ? "innerText" : "textContent"])) {
					start[browser.ie ? "innerText" : "textContent"] = utils.html(opt.textValue || opt.href)
				}
			}
			if (!rngClone.collapsed || link) {
				range.removeInlineStyle("a");
				rngClone = range.cloneRange()
			}
			if (rngClone.collapsed) {
				var a = range.document.createElement("a"),
					text = "";
				if (opt.textValue) {
					text = utils.html(opt.textValue);
					delete opt.textValue
				} else {
					text = utils.html(opt.href)
				}
				domUtils.setAttributes(a, opt);
				start = domUtils.findParentByTagName(rngClone.startContainer, "a", true);
				if (start && domUtils.isInNodeEndBoundary(rngClone, start)) {
					range.setStartAfter(start).collapse(true)
				}
				a[browser.ie ? "innerText" : "textContent"] = text;
				range.insertNode(a).selectNode(a)
			} else {
				range.applyInlineStyle("a", opt)
			}
		}
		UE.commands["link"] = {
			execCommand: function(cmdName, opt) {
				var range;
				opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g));
				opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g));
				opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g));
				doLink(range = this.selection.getRange(), opt, this);
				range.collapse().select(true)
			},
			queryCommandValue: function() {
				var range = this.selection.getRange(),
					node;
				if (range.collapsed) {
					node = range.startContainer;
					node = node.nodeType == 1 ? node : node.parentNode;
					if (node && (node = domUtils.findParentByTagName(node, "a", true)) && !domUtils
						.isInNodeEndBoundary(range, node)) {
						return node
					}
				} else {
					range.shrinkBoundary();
					var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[
							range.startOffset] ? range.startContainer : range.startContainer.childNodes[
							range.startOffset],
						end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range
						.endContainer : range.endContainer.childNodes[range.endOffset - 1],
						common = range.getCommonAncestor();
					node = domUtils.findParentByTagName(common, "a", true);
					if (!node && common.nodeType == 1) {
						var as = common.getElementsByTagName("a"),
							ps, pe;
						for (var i = 0, ci; ci = as[i++];) {
							ps = domUtils.getPosition(ci, start), pe = domUtils.getPosition(ci, end);
							if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS) &&
								(pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)) {
								node = ci;
								break
							}
						}
					}
					return node
				}
			},
			queryCommandState: function() {
				var img = this.selection.getRange().getClosedNode(),
					flag = img && (img.className == "edui-faked-video" || img.className.indexOf(
						"edui-upload-video") != -1);
				return flag ? -1 : 0
			}
		}
	};
	UE.plugins["insertframe"] = function() {
		var me = this;

		function deleteIframe() {
			me._iframe && delete me._iframe
		}
		me.addListener("selectionchange", function() {
			deleteIframe()
		})
	};
	UE.commands["scrawl"] = {
		queryCommandState: function() {
			return browser.ie && browser.version <= 8 ? -1 : 0
		}
	};
	UE.plugins["removeformat"] = function() {
		var me = this;
		me.setOpt({
			removeFormatTags: "b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var",
			removeFormatAttributes: "class,style,lang,width,height,align,hspace,valign"
		});
		me.commands["removeformat"] = {
			execCommand: function(cmdName, tags, style, attrs, notIncludeA) {
				var tagReg = new RegExp("^(?:" + (tags || this.options.removeFormatTags).replace(/,/g,
						"|") + ")$", "i"),
					removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes)
					.split(","),
					range = new dom.Range(this.document),
					bookmark, node, parent, filter = function(node) {
						return node.nodeType == 1
					};

				function isRedundantSpan(node) {
					if (node.nodeType == 3 || node.tagName.toLowerCase() != "span") {
						return 0
					}
					if (browser.ie) {
						var attrs = node.attributes;
						if (attrs.length) {
							for (var i = 0, l = attrs.length; i < l; i++) {
								if (attrs[i].specified) {
									return 0
								}
							}
							return 1
						}
					}
					return !node.attributes.length
				}

				function doRemove(range) {
					var bookmark1 = range.createBookmark();
					if (range.collapsed) {
						range.enlarge(true)
					}
					if (!notIncludeA) {
						var aNode = domUtils.findParentByTagName(range.startContainer, "a", true);
						if (aNode) {
							range.setStartBefore(aNode)
						}
						aNode = domUtils.findParentByTagName(range.endContainer, "a", true);
						if (aNode) {
							range.setEndAfter(aNode)
						}
					}
					bookmark = range.createBookmark();
					node = bookmark.start;
					while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
						domUtils.breakParent(node, parent);
						domUtils.clearEmptySibling(node)
					}
					if (bookmark.end) {
						node = bookmark.end;
						while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
							domUtils.breakParent(node, parent);
							domUtils.clearEmptySibling(node)
						}
						var current = domUtils.getNextDomNode(bookmark.start, false, filter),
							next;
						while (current) {
							if (current == bookmark.end) {
								break
							}
							next = domUtils.getNextDomNode(current, true, filter);
							if (!dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode(
									current)) {
								if (tagReg.test(current.tagName)) {
									if (style) {
										domUtils.removeStyle(current, style);
										if (isRedundantSpan(current) && style != "text-decoration") {
											domUtils.remove(current, true)
										}
									} else {
										domUtils.remove(current, true)
									}
								} else {
									if (true) {
										domUtils.removeAttributes(current, removeFormatAttributes);
										if (isRedundantSpan(current)) {
											domUtils.remove(current, true)
										}
									} else {}
								}
							}
							current = next
						}
					}
					var pN = bookmark.start.parentNode;
					if (domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN
							.tagName]) {
						domUtils.removeAttributes(pN, removeFormatAttributes)
					}
					pN = bookmark.end.parentNode;
					if (bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !
						dtd.$list[pN.tagName]) {
						domUtils.removeAttributes(pN, removeFormatAttributes)
					}
					range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
					var node = range.startContainer,
						tmp, collapsed = range.collapsed;
					while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node
							.tagName]) {
						tmp = node.parentNode;
						range.setStartBefore(node);
						if (range.startContainer === range.endContainer) {
							range.endOffset--
						}
						domUtils.remove(node);
						node = tmp
					}
					if (!collapsed) {
						node = range.endContainer;
						while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node
								.tagName]) {
							tmp = node.parentNode;
							range.setEndBefore(node);
							domUtils.remove(node);
							node = tmp
						}
					}
				}
				range = this.selection.getRange();
				doRemove(range);
				range.select()
			}
		}
	};
	UE.plugins["blockquote"] = function() {
		var me = this;

		function getObj(editor) {
			return domUtils.filterNodeList(editor.selection.getStartElementPath(), "blockquote")
		}
		me.commands["blockquote"] = {
			execCommand: function(cmdName, attrs) {
				var range = this.selection.getRange(),
					obj = getObj(this),
					blockquote = dtd.blockquote,
					bookmark = range.createBookmark();
				if (obj) {
					var start = range.startContainer,
						startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start,
							function(node) {
								return domUtils.isBlockElm(node)
							}),
						end = range.endContainer,
						endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end, function(
							node) {
							return domUtils.isBlockElm(node)
						});
					startBlock = domUtils.findParentByTagName(startBlock, "li", true) || startBlock;
					endBlock = domUtils.findParentByTagName(endBlock, "li", true) || endBlock;
					if (startBlock.tagName == "LI" || startBlock.tagName == "TD" || startBlock ===
						obj || domUtils.isBody(startBlock)) {
						domUtils.remove(obj, true)
					} else {
						domUtils.breakParent(startBlock, obj)
					}
					if (startBlock !== endBlock) {
						obj = domUtils.findParentByTagName(endBlock, "blockquote");
						if (obj) {
							if (endBlock.tagName == "LI" || endBlock.tagName == "TD" || domUtils.isBody(
									endBlock)) {
								obj.parentNode && domUtils.remove(obj, true)
							} else {
								domUtils.breakParent(endBlock, obj)
							}
						}
					}
					var blockquotes = domUtils.getElementsByTagName(this.document, "blockquote");
					for (var i = 0, bi; bi = blockquotes[i++];) {
						if (!bi.childNodes.length) {
							domUtils.remove(bi)
						} else if (domUtils.getPosition(bi, startBlock) & domUtils.POSITION_FOLLOWING &&
							domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING) {
							domUtils.remove(bi, true)
						}
					}
				} else {
					var tmpRange = range.cloneRange(),
						node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer :
						tmpRange.startContainer.parentNode,
						preNode = node,
						doEnd = 1;
					while (1) {
						if (domUtils.isBody(node)) {
							if (preNode !== node) {
								if (range.collapsed) {
									tmpRange.selectNode(preNode);
									doEnd = 0
								} else {
									tmpRange.setStartBefore(preNode)
								}
							} else {
								tmpRange.setStart(node, 0)
							}
							break
						}
						if (!blockquote[node.tagName]) {
							if (range.collapsed) {
								tmpRange.selectNode(preNode)
							} else {
								tmpRange.setStartBefore(preNode)
							}
							break
						}
						preNode = node;
						node = node.parentNode
					}
					if (doEnd) {
						preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange
							.endContainer : tmpRange.endContainer.parentNode;
						while (1) {
							if (domUtils.isBody(node)) {
								if (preNode !== node) {
									tmpRange.setEndAfter(preNode)
								} else {
									tmpRange.setEnd(node, node.childNodes.length)
								}
								break
							}
							if (!blockquote[node.tagName]) {
								tmpRange.setEndAfter(preNode);
								break
							}
							preNode = node;
							node = node.parentNode
						}
					}
					node = range.document.createElement("blockquote");
					domUtils.setAttributes(node, attrs);
					node.appendChild(tmpRange.extractContents());
					tmpRange.insertNode(node);
					var childs = domUtils.getElementsByTagName(node, "blockquote");
					for (var i = 0, ci; ci = childs[i++];) {
						if (ci.parentNode) {
							domUtils.remove(ci, true)
						}
					}
				}
				range.moveToBookmark(bookmark).select()
			},
			queryCommandState: function() {
				return getObj(this) ? 1 : 0
			}
		}
	};
	UE.commands["touppercase"] = UE.commands["tolowercase"] = {
		execCommand: function(cmd) {
			var me = this;
			var rng = me.selection.getRange();
			if (rng.collapsed) {
				return rng
			}
			var bk = rng.createBookmark(),
				bkEnd = bk.end,
				filterFn = function(node) {
					return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
				},
				curNode = domUtils.getNextDomNode(bk.start, false, filterFn);
			while (curNode && domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING) {
				if (curNode.nodeType == 3) {
					curNode.nodeValue = curNode.nodeValue[cmd == "touppercase" ? "toUpperCase" :
						"toLowerCase"]()
				}
				curNode = domUtils.getNextDomNode(curNode, true, filterFn);
				if (curNode === bkEnd) {
					break
				}
			}
			rng.moveToBookmark(bk).select()
		}
	};
	UE.commands["indent"] = {
		execCommand: function() {
			var me = this,
				value = me.queryCommandState("indent") ? "0em" : me.options.indentValue || "2em";
			me.execCommand("Paragraph", "p", {
				style: "text-indent:" + value
			})
		},
		queryCommandState: function() {
			var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), "p h1 h2 h3 h4 h5 h6");
			return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0
		}
	};
	UE.commands["print"] = {
		execCommand: function() {
			this.window.print()
		},
		notNeedUndo: 1
	};
	UE.commands["preview"] = {
		execCommand: function() {
			var w = window.open("", "_blank", ""),
				d = w.document;
			d.open();
			d.write('<!DOCTYPE html><html><head><meta charset="utf-8"/><script src="' + this.options
				.UEDITOR_HOME_URL + 'ueditor.parse.js"><\/script><script>' +
				"setTimeout(function(){uParse('div',{rootPath: '" + this.options.UEDITOR_HOME_URL +
				"'})},300)" + "<\/script></head><body><div>" + this.getContent(null, null, true) +
				"</div></body></html>");
			d.close()
		},
		notNeedUndo: 1
	};
	UE.plugins["selectall"] = function() {
		var me = this;
		me.commands["selectall"] = {
			execCommand: function() {
				var me = this,
					body = me.body,
					range = me.selection.getRange();
				range.selectNodeContents(body);
				if (domUtils.isEmptyBlock(body)) {
					if (browser.opera && body.firstChild && body.firstChild.nodeType == 1) {
						range.setStartAtFirst(body.firstChild)
					}
					range.collapse(true)
				}
				range.select(true)
			},
			notNeedUndo: 1
		};
		me.addshortcutkey({
			selectAll: "ctrl+65"
		})
	};
	UE.plugins["paragraph"] = function() {
		var me = this,
			block = domUtils.isBlockElm,
			notExchange = ["TD", "LI", "PRE"],
			doParagraph = function(range, style, attrs, sourceCmdName) {
				var bookmark = range.createBookmark(),
					filterFn = function(node) {
						return node.nodeType == 1 ? node.tagName.toLowerCase() != "br" && !domUtils
							.isBookmarkNode(node) : !domUtils.isWhitespace(node)
					},
					para;
				range.enlarge(true);
				var bookmark2 = range.createBookmark(),
					current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
					tmpRange = range.cloneRange(),
					tmpNode;
				while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils
					.POSITION_FOLLOWING)) {
					if (current.nodeType === 3 || !block(current)) {
						tmpRange.setStartBefore(current);
						while (current && current !== bookmark2.end && !block(current)) {
							tmpNode = current;
							current = domUtils.getNextDomNode(current, false, null, function(node) {
								return !block(node)
							})
						}
						tmpRange.setEndAfter(tmpNode);
						para = range.document.createElement(style);
						if (attrs) {
							domUtils.setAttributes(para, attrs);
							if (sourceCmdName && sourceCmdName === "customstyle" && attrs.style) {
								para.style.cssText = attrs.style
							}
						}
						para.appendChild(tmpRange.extractContents());
						if (domUtils.isEmptyNode(para)) {
							domUtils.fillChar(range.document, para)
						}
						tmpRange.insertNode(para);
						var parent = para.parentNode;
						if (block(parent) && !domUtils.isBody(para.parentNode) && utils.indexOf(notExchange,
								parent.tagName) === -1) {
							if (!(sourceCmdName && sourceCmdName === "customstyle")) {
								parent.getAttribute("dir") && para.setAttribute("dir", parent.getAttribute(
									"dir"));
								parent.style.cssText && (para.style.cssText = parent.style.cssText + ";" + para
									.style.cssText);
								parent.style.textAlign && !para.style.textAlign && (para.style.textAlign =
									parent.style.textAlign);
								parent.style.textIndent && !para.style.textIndent && (para.style.textIndent =
									parent.style.textIndent);
								parent.style.padding && !para.style.padding && (para.style.padding = parent
									.style.padding)
							}
							if (attrs && /h\d/i.test(parent.tagName) && !/h\d/i.test(para.tagName)) {
								domUtils.setAttributes(parent, attrs);
								if (sourceCmdName && sourceCmdName === "customstyle" && attrs.style) {
									parent.style.cssText = attrs.style
								}
								domUtils.remove(para.parentNode, true);
								para = parent
							} else {
								domUtils.remove(para.parentNode, true)
							}
						}
						if (utils.indexOf(notExchange, parent.tagName) !== -1) {
							current = parent
						} else {
							current = para
						}
						current = domUtils.getNextDomNode(current, false, filterFn)
					} else {
						current = domUtils.getNextDomNode(current, true, filterFn)
					}
				}
				return range.moveToBookmark(bookmark2).moveToBookmark(bookmark)
			};
		me.setOpt("paragraph", {
			p: "",
			h1: "",
			h2: "",
			h3: "",
			h4: "",
			h5: "",
			h6: ""
		});
		me.commands["paragraph"] = {
			execCommand: function(cmdName, style, attrs, sourceCmdName) {
				var range = this.selection.getRange();
				if (range.collapsed) {
					var txt = this.document.createTextNode("p");
					range.insertNode(txt);
					if (browser.ie) {
						var node = txt.previousSibling;
						if (node && domUtils.isWhitespace(node)) {
							domUtils.remove(node)
						}
						node = txt.nextSibling;
						if (node && domUtils.isWhitespace(node)) {
							domUtils.remove(node)
						}
					}
				}
				range = doParagraph(range, style, attrs, sourceCmdName);
				if (txt) {
					range.setStartBefore(txt).collapse(true);
					pN = txt.parentNode;
					domUtils.remove(txt);
					if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) {
						domUtils.fillNode(this.document, pN)
					}
				}
				if (browser.gecko && range.collapsed && range.startContainer.nodeType === 1) {
					var child = range.startContainer.childNodes[range.startOffset];
					if (child && child.nodeType === 1 && child.tagName.toLowerCase() === style) {
						range.setStart(child, 0).collapse(true)
					}
				}
				range.select();
				return true
			},
			queryCommandValue: function() {
				var node = domUtils.filterNodeList(this.selection.getStartElementPath(),
					"p h1 h2 h3 h4 h5 h6");
				return node ? node.tagName.toLowerCase() : ""
			}
		}
	};
	(function() {
		var block = domUtils.isBlockElm,
			getObj = function(editor) {
				return domUtils.filterNodeList(editor.selection.getStartElementPath(), function(n) {
					return n && n.nodeType == 1 && n.getAttribute("dir")
				})
			},
			doDirectionality = function(range, editor, forward) {
				var bookmark, filterFn = function(node) {
						return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(
							node)
					},
					obj = getObj(editor);
				if (obj && range.collapsed) {
					obj.setAttribute("dir", forward);
					return range
				}
				bookmark = range.createBookmark();
				range.enlarge(true);
				var bookmark2 = range.createBookmark(),
					current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
					tmpRange = range.cloneRange(),
					tmpNode;
				while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils
					.POSITION_FOLLOWING)) {
					if (current.nodeType == 3 || !block(current)) {
						tmpRange.setStartBefore(current);
						while (current && current !== bookmark2.end && !block(current)) {
							tmpNode = current;
							current = domUtils.getNextDomNode(current, false, null, function(node) {
								return !block(node)
							})
						}
						tmpRange.setEndAfter(tmpNode);
						var common = tmpRange.getCommonAncestor();
						if (!domUtils.isBody(common) && block(common)) {
							common.setAttribute("dir", forward);
							current = common
						} else {
							var p = range.document.createElement("p");
							p.setAttribute("dir", forward);
							var frag = tmpRange.extractContents();
							p.appendChild(frag);
							tmpRange.insertNode(p);
							current = p
						}
						current = domUtils.getNextDomNode(current, false, filterFn)
					} else {
						current = domUtils.getNextDomNode(current, true, filterFn)
					}
				}
				return range.moveToBookmark(bookmark2).moveToBookmark(bookmark)
			};
		UE.commands["directionality"] = {
			execCommand: function(cmdName, forward) {
				var range = this.selection.getRange();
				if (range.collapsed) {
					var txt = this.document.createTextNode("d");
					range.insertNode(txt)
				}
				doDirectionality(range, this, forward);
				if (txt) {
					range.setStartBefore(txt).collapse(true);
					domUtils.remove(txt)
				}
				range.select();
				return true
			},
			queryCommandValue: function() {
				var node = getObj(this);
				return node ? node.getAttribute("dir") : "ltr"
			}
		}
	})();
	UE.plugins["horizontal"] = function() {
		var me = this;
		me.commands["horizontal"] = {
			execCommand: function(cmdName) {
				var me = this;
				if (me.queryCommandState(cmdName) !== -1) {
					me.execCommand("insertHtml", "<hr>");
					var range = me.selection.getRange(),
						start = range.startContainer;
					if (start.nodeType == 1 && !start.childNodes[range.startOffset]) {
						var tmp;
						if (tmp = start.childNodes[range.startOffset - 1]) {
							if (tmp.nodeType == 1 && tmp.tagName == "HR") {
								if (me.options.enterTag == "p") {
									tmp = me.document.createElement("p");
									range.insertNode(tmp);
									range.setStart(tmp, 0).setCursor()
								} else {
									tmp = me.document.createElement("br");
									range.insertNode(tmp);
									range.setStartBefore(tmp).setCursor()
								}
							}
						}
					}
					return true
				}
			},
			queryCommandState: function() {
				return domUtils.filterNodeList(this.selection.getStartElementPath(), "table") ? -1 : 0
			}
		};
		me.addListener("delkeydown", function(name, evt) {
			var rng = this.selection.getRange();
			rng.txtToElmBoundary(true);
			if (domUtils.isStartInblock(rng)) {
				var tmpNode = rng.startContainer;
				var pre = tmpNode.previousSibling;
				if (pre && domUtils.isTagNode(pre, "hr")) {
					domUtils.remove(pre);
					rng.select();
					domUtils.preventDefault(evt);
					return true
				}
			}
		})
	};
	UE.commands["time"] = UE.commands["date"] = {
		execCommand: function(cmd, format) {
			var date = new Date;

			function formatTime(date, format) {
				var hh = ("0" + date.getHours()).slice(-2),
					ii = ("0" + date.getMinutes()).slice(-2),
					ss = ("0" + date.getSeconds()).slice(-2);
				format = format || "hh:ii:ss";
				return format.replace(/hh/gi, hh).replace(/ii/gi, ii).replace(/ss/gi, ss)
			}

			function formatDate(date, format) {
				var yyyy = ("000" + date.getFullYear()).slice(-4),
					yy = yyyy.slice(-2),
					mm = ("0" + (date.getMonth() + 1)).slice(-2),
					dd = ("0" + date.getDate()).slice(-2);
				format = format || "yyyy-mm-dd";
				return format.replace(/yyyy/gi, yyyy).replace(/yy/gi, yy).replace(/mm/gi, mm).replace(
					/dd/gi, dd)
			}
			this.execCommand("insertHtml", cmd == "time" ? formatTime(date, format) : formatDate(date,
				format))
		}
	};
	UE.plugins["rowspacing"] = function() {
		var me = this;
		me.setOpt({
			rowspacingtop: ["5", "10", "15", "20", "25"],
			rowspacingbottom: ["5", "10", "15", "20", "25"]
		});
		me.commands["rowspacing"] = {
			execCommand: function(cmdName, value, dir) {
				this.execCommand("paragraph", "p", {
					style: "margin-" + dir + ":" + value + "px"
				});
				return true
			},
			queryCommandValue: function(cmdName, dir) {
				var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function(node) {
						return domUtils.isBlockElm(node)
					}),
					value;
				if (pN) {
					value = domUtils.getComputedStyle(pN, "margin-" + dir).replace(/[^\d]/g, "");
					return !value ? 0 : value
				}
				return 0
			}
		}
	};
	UE.plugins["lineheight"] = function() {
		var me = this;
		me.setOpt({
			lineheight: ["1", "1.5", "1.75", "2", "3", "4", "5"]
		});
		me.commands["lineheight"] = {
			execCommand: function(cmdName, value) {
				this.execCommand("paragraph", "p", {
					style: "line-height:" + (value == "1" ? "normal" : value + "em")
				});
				return true
			},
			queryCommandValue: function() {
				var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function(node) {
					return domUtils.isBlockElm(node)
				});
				if (pN) {
					var value = domUtils.getComputedStyle(pN, "line-height");
					return value == "normal" ? 1 : value.replace(/[^\d.]*/gi, "")
				}
			}
		}
	};
	UE.plugins["insertcode"] = function() {
		var me = this;
		me.setOpt("insertcode", {
			as3: "ActionScript3",
			bash: "Bash/Shell",
			cpp: "C/C++",
			css: "Css",
			"c#": "C#",
			delphi: "Delphi",
			erlang: "Erlang",
			groovy: "Groovy",
			html: "Html",
			java: "Java",
			js: "Javascript",
			pl: "Perl",
			php: "PHP",
			plain: "Text",
			ps: "PowerShell",
			python: "Python",
			ruby: "Ruby",
			scala: "Scala",
			sql: "SQL",
			vb: "VB",
			xml: "XML",
			mind: "Mind"
		});
		me.commands["insertcode"] = {
			execCommand: function(cmd, lang) {
				var me = this,
					rng = me.selection.getRange(),
					pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
				if (pre) {
					pre.className = "brush:" + lang + ";toolbar:false;"
				} else {
					var code = "";
					if (rng.collapsed) {
						code = browser.ie && browser.ie11below ? browser.version <= 8 ? "&nbsp;" : "" :
							"<br/>"
					} else {
						var frag = rng.extractContents();
						var div = me.document.createElement("div");
						div.appendChild(frag);
						utils.each(UE.filterNode(UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, "")), me
							.options.filterTxtRules).children, function(node) {
							if (browser.ie && browser.ie11below && browser.version > 8) {
								if (node.type == "element") {
									if (node.tagName == "br") {
										code += "\n"
									} else if (!dtd.$empty[node.tagName]) {
										utils.each(node.children, function(cn) {
											if (cn.type == "element") {
												if (cn.tagName == "br") {
													code += "\n"
												} else if (!dtd.$empty[node.tagName]) {
													code += cn.innerText()
												}
											} else {
												code += cn.data
											}
										});
										if (!/\n$/.test(code)) {
											code += "\n"
										}
									}
								} else {
									code += node.data + "\n"
								}
								if (!node.nextSibling() && /\n$/.test(code)) {
									code = code.replace(/\n$/, "")
								}
							} else {
								if (browser.ie && browser.ie11below) {
									if (node.type == "element") {
										if (node.tagName == "br") {
											code += "<br>"
										} else if (!dtd.$empty[node.tagName]) {
											utils.each(node.children, function(cn) {
												if (cn.type == "element") {
													if (cn.tagName == "br") {
														code += "<br>"
													} else if (!dtd.$empty[node
														.tagName]) {
														code += cn.innerText()
													}
												} else {
													code += cn.data
												}
											});
											if (!/br>$/.test(code)) {
												code += "<br>"
											}
										}
									} else {
										code += node.data + "<br>"
									}
									if (!node.nextSibling() && /<br>$/.test(code)) {
										code = code.replace(/<br>$/, "")
									}
								} else {
									code += node.type == "element" ? dtd.$empty[node.tagName] ?
										"" : node.innerText() : node.data;
									if (!/br\/?\s*>$/.test(code)) {
										if (!node.nextSibling()) return;
										code += "<br>"
									}
								}
							}
						})
					}
					me.execCommand("inserthtml", '<pre id="coder"class="brush:' + lang +
						';toolbar:false">' + code + "</pre>", true);
					pre = me.document.getElementById("coder");
					domUtils.removeAttributes(pre, "id");
					var tmpNode = pre.previousSibling;
					if (tmpNode && (tmpNode.nodeType == 3 && tmpNode.nodeValue.length == 1 && browser
							.ie && browser.version == 6 || domUtils.isEmptyBlock(tmpNode))) {
						domUtils.remove(tmpNode)
					}
					var rng = me.selection.getRange();
					if (domUtils.isEmptyBlock(pre)) {
						rng.setStart(pre, 0).setCursor(false, true)
					} else {
						rng.selectNodeContents(pre).select()
					}
				}
			},
			queryCommandValue: function() {
				var path = this.selection.getStartElementPath();
				var lang = "";
				utils.each(path, function(node) {
					if (node.nodeName == "PRE") {
						var match = node.className.match(/brush:([^;]+)/);
						lang = match && match[1] ? match[1] : "";
						return false
					}
				});
				return lang
			}
		};
		me.addInputRule(function(root) {
			utils.each(root.getNodesByTagName("pre"), function(pre) {
				var brs = pre.getNodesByTagName("br");
				if (brs.length) {
					browser.ie && browser.ie11below && browser.version > 8 && utils.each(brs,
						function(br) {
							var txt = UE.uNode.createText("\n");
							br.parentNode.insertBefore(txt, br);
							br.parentNode.removeChild(br)
						});
					return
				}
				if (browser.ie && browser.ie11below && browser.version > 8) return;
				var code = pre.innerText().split(/\n/);
				pre.innerHTML("");
				utils.each(code, function(c) {
					if (c.length) {
						pre.appendChild(UE.uNode.createText(c))
					}
					pre.appendChild(UE.uNode.createElement("br"))
				})
			})
		});
		me.addOutputRule(function(root) {
			utils.each(root.getNodesByTagName("pre"), function(pre) {
				var code = "";
				utils.each(pre.children, function(n) {
					if (n.type == "text") {
						code += n.data.replace(/[ ]/g, "&nbsp;").replace(/\n$/, "")
					} else {
						if (n.tagName == "br") {
							code += "\n"
						} else {
							code += !dtd.$empty[n.tagName] ? "" : n.innerText()
						}
					}
				});
				pre.innerText(code.replace(/(&nbsp;|\n)+$/, ""))
			})
		});
		me.notNeedCodeQuery = {
			help: 1,
			undo: 1,
			redo: 1,
			source: 1,
			print: 1,
			searchreplace: 1,
			fullscreen: 1,
			preview: 1,
			insertparagraph: 1,
			elementpath: 1,
			insertcode: 1,
			inserthtml: 1,
			selectall: 1
		};
		var orgQuery = me.queryCommandState;
		me.queryCommandState = function(cmd) {
			var me = this;
			if (!me.notNeedCodeQuery[cmd.toLowerCase()] && me.selection && me.queryCommandValue(
					"insertcode")) {
				return -1
			}
			return UE.Editor.prototype.queryCommandState.apply(this, arguments)
		};
		me.addListener("beforeenterkeydown", function() {
			var rng = me.selection.getRange();
			var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
			if (pre) {
				me.fireEvent("saveScene");
				if (!rng.collapsed) {
					rng.deleteContents()
				}
				if (!browser.ie || browser.ie9above) {
					var tmpNode = me.document.createElement("br"),
						pre;
					rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
					var next = tmpNode.nextSibling;
					if (!next && (!browser.ie || browser.version > 10)) {
						rng.insertNode(tmpNode.cloneNode(false))
					} else {
						rng.setStartAfter(tmpNode)
					}
					pre = tmpNode.previousSibling;
					var tmp;
					while (pre) {
						tmp = pre;
						pre = pre.previousSibling;
						if (!pre || pre.nodeName == "BR") {
							pre = tmp;
							break
						}
					}
					if (pre) {
						var str = "";
						while (pre && pre.nodeName != "BR" && new RegExp("^[\\s" + domUtils.fillChar +
								"]*$").test(pre.nodeValue)) {
							str += pre.nodeValue;
							pre = pre.nextSibling
						}
						if (pre.nodeName != "BR") {
							var match = pre.nodeValue.match(new RegExp("^([\\s" + domUtils.fillChar +
								"]+)"));
							if (match && match[1]) {
								str += match[1]
							}
						}
						if (str) {
							str = me.document.createTextNode(str);
							rng.insertNode(str).setStartAfter(str)
						}
					}
					rng.collapse(true).select(true)
				} else {
					if (browser.version > 8) {
						var txt = me.document.createTextNode("\n");
						var start = rng.startContainer;
						if (rng.startOffset == 0) {
							var preNode = start.previousSibling;
							if (preNode) {
								rng.insertNode(txt);
								var fillchar = me.document.createTextNode(" ");
								rng.setStartAfter(txt).insertNode(fillchar).setStart(fillchar, 0)
									.collapse(true).select(true)
							}
						} else {
							rng.insertNode(txt).setStartAfter(txt);
							var fillchar = me.document.createTextNode(" ");
							start = rng.startContainer.childNodes[rng.startOffset];
							if (start && !/^\n/.test(start.nodeValue)) {
								rng.setStartBefore(txt)
							}
							rng.insertNode(fillchar).setStart(fillchar, 0).collapse(true).select(true)
						}
					} else {
						var tmpNode = me.document.createElement("br");
						rng.insertNode(tmpNode);
						rng.insertNode(me.document.createTextNode(domUtils.fillChar));
						rng.setStartAfter(tmpNode);
						pre = tmpNode.previousSibling;
						var tmp;
						while (pre) {
							tmp = pre;
							pre = pre.previousSibling;
							if (!pre || pre.nodeName == "BR") {
								pre = tmp;
								break
							}
						}
						if (pre) {
							var str = "";
							while (pre && pre.nodeName != "BR" && new RegExp("^[ " + domUtils.fillChar +
									"]*$").test(pre.nodeValue)) {
								str += pre.nodeValue;
								pre = pre.nextSibling
							}
							if (pre.nodeName != "BR") {
								var match = pre.nodeValue.match(new RegExp("^([ " + domUtils.fillChar +
									"]+)"));
								if (match && match[1]) {
									str += match[1]
								}
							}
							str = me.document.createTextNode(str);
							rng.insertNode(str).setStartAfter(str)
						}
						rng.collapse(true).select()
					}
				}
				me.fireEvent("saveScene");
				return true
			}
		});
		me.addListener("tabkeydown", function(cmd, evt) {
			var rng = me.selection.getRange();
			var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
			if (pre) {
				me.fireEvent("saveScene");
				if (evt.shiftKey) {} else {
					if (!rng.collapsed) {
						var bk = rng.createBookmark();
						var start = bk.start.previousSibling;
						while (start) {
							if (pre.firstChild === start && !domUtils.isBr(start)) {
								pre.insertBefore(me.document.createTextNode("    "), start);
								break
							}
							if (domUtils.isBr(start)) {
								pre.insertBefore(me.document.createTextNode("    "), start.nextSibling);
								break
							}
							start = start.previousSibling
						}
						var end = bk.end;
						start = bk.start.nextSibling;
						if (pre.firstChild === bk.start) {
							pre.insertBefore(me.document.createTextNode("    "), start.nextSibling)
						}
						while (start && start !== end) {
							if (domUtils.isBr(start) && start.nextSibling) {
								if (start.nextSibling === end) {
									break
								}
								pre.insertBefore(me.document.createTextNode("    "), start.nextSibling)
							}
							start = start.nextSibling
						}
						rng.moveToBookmark(bk).select()
					} else {
						var tmpNode = me.document.createTextNode("    ");
						rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true).select(true)
					}
				}
				me.fireEvent("saveScene");
				return true
			}
		});
		me.addListener("beforeinserthtml", function(evtName, html) {
			var me = this,
				rng = me.selection.getRange(),
				pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
			if (pre) {
				if (!rng.collapsed) {
					rng.deleteContents()
				}
				var htmlstr = "";
				if (browser.ie && browser.version > 8) {
					utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children,
						function(node) {
							if (node.type == "element") {
								if (node.tagName == "br") {
									htmlstr += "\n"
								} else if (!dtd.$empty[node.tagName]) {
									utils.each(node.children, function(cn) {
										if (cn.type == "element") {
											if (cn.tagName == "br") {
												htmlstr += "\n"
											} else if (!dtd.$empty[node.tagName]) {
												htmlstr += cn.innerText()
											}
										} else {
											htmlstr += cn.data
										}
									});
									if (!/\n$/.test(htmlstr)) {
										htmlstr += "\n"
									}
								}
							} else {
								htmlstr += node.data + "\n"
							}
							if (!node.nextSibling() && /\n$/.test(htmlstr)) {
								htmlstr = htmlstr.replace(/\n$/, "")
							}
						});
					var tmpNode = me.document.createTextNode(utils.html(htmlstr.replace(/&nbsp;/g,
						" ")));
					rng.insertNode(tmpNode).selectNode(tmpNode).select()
				} else {
					var frag = me.document.createDocumentFragment();
					utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children,
						function(node) {
							if (node.type == "element") {
								if (node.tagName == "br") {
									frag.appendChild(me.document.createElement("br"))
								} else if (!dtd.$empty[node.tagName]) {
									utils.each(node.children, function(cn) {
										if (cn.type == "element") {
											if (cn.tagName == "br") {
												frag.appendChild(me.document.createElement(
													"br"))
											} else if (!dtd.$empty[node.tagName]) {
												frag.appendChild(me.document.createTextNode(
													utils.html(cn.innerText()
														.replace(/&nbsp;/g, " "))))
											}
										} else {
											frag.appendChild(me.document.createTextNode(
												utils.html(cn.data.replace(
													/&nbsp;/g, " "))))
										}
									});
									if (frag.lastChild.nodeName != "BR") {
										frag.appendChild(me.document.createElement("br"))
									}
								}
							} else {
								frag.appendChild(me.document.createTextNode(utils.html(node.data
									.replace(/&nbsp;/g, " "))))
							}
							if (!node.nextSibling() && frag.lastChild.nodeName == "BR") {
								frag.removeChild(frag.lastChild)
							}
						});
					rng.insertNode(frag).select()
				}
				return true
			}
		});
		me.addListener("keydown", function(cmd, evt) {
			var me = this,
				keyCode = evt.keyCode || evt.which;
			if (keyCode == 40) {
				var rng = me.selection.getRange(),
					pre, start = rng.startContainer;
				if (rng.collapsed && (pre = domUtils.findParentByTagName(rng.startContainer, "pre",
						true)) && !pre.nextSibling) {
					var last = pre.lastChild;
					while (last && last.nodeName == "BR") {
						last = last.previousSibling
					}
					if (last === start || rng.startContainer === pre && rng.startOffset == pre
						.childNodes.length) {
						me.execCommand("insertparagraph");
						domUtils.preventDefault(evt)
					}
				}
			}
		});
		me.addListener("delkeydown", function(type, evt) {
			var rng = this.selection.getRange();
			rng.txtToElmBoundary(true);
			var start = rng.startContainer;
			if (domUtils.isTagNode(start, "pre") && rng.collapsed && domUtils.isStartInblock(rng)) {
				var p = me.document.createElement("p");
				domUtils.fillNode(me.document, p);
				start.parentNode.insertBefore(p, start);
				domUtils.remove(start);
				rng.setStart(p, 0).setCursor(false, true);
				domUtils.preventDefault(evt);
				return true
			}
		})
	};
	UE.commands["cleardoc"] = {
		execCommand: function(cmdName) {
			var me = this,
				enterTag = me.options.enterTag,
				range = me.selection.getRange();
			if (enterTag == "br") {
				me.body.innerHTML = "<br/>";
				range.setStart(me.body, 0).setCursor()
			} else {
				me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
				range.setStart(me.body.firstChild, 0).setCursor(false, true)
			}
			setTimeout(function() {
				me.fireEvent("clearDoc")
			}, 0)
		}
	};
	UE.plugin.register("anchor", function() {
		return {
			bindEvents: {
				ready: function() {
					utils.cssRule("anchor", ".anchorclass{background: url('" + this.options.themePath +
						this.options.theme +
						"/images/anchor.gif') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}",
						this.document)
				}
			},
			outputRule: function(root) {
				utils.each(root.getNodesByTagName("img"), function(a) {
					var val;
					if (val = a.getAttr("anchorname")) {
						a.tagName = "a";
						a.setAttr({
							anchorname: "",
							name: val,
							class: ""
						})
					}
				})
			},
			inputRule: function(root) {
				utils.each(root.getNodesByTagName("a"), function(a) {
					var val;
					if ((val = a.getAttr("name")) && !a.getAttr("href")) {
						if (/^\_Toc\d+$/.test(val)) {
							a.parentNode.removeChild(a);
							return
						}
						a.tagName = "img";
						a.setAttr({
							anchorname: a.getAttr("name"),
							class: "anchorclass"
						});
						a.setAttr("name")
					}
				})
			},
			commands: {
				anchor: {
					execCommand: function(cmd, name) {
						var range = this.selection.getRange(),
							img = range.getClosedNode();
						if (img && img.getAttribute("anchorname")) {
							if (name) {
								img.setAttribute("anchorname", name)
							} else {
								range.setStartBefore(img).setCursor();
								domUtils.remove(img)
							}
						} else {
							if (name) {
								var anchor = this.document.createElement("img");
								range.collapse(true);
								domUtils.setAttributes(anchor, {
									anchorname: name,
									class: "anchorclass"
								});
								range.insertNode(anchor).setStartAfter(anchor).setCursor(false, true)
							}
						}
					}
				}
			}
		}
	});
	UE.plugins["wordcount"] = function() {
		var me = this;
		me.setOpt("wordCount", true);
		me.addListener("contentchange", function() {
			me.fireEvent("wordcount")
		});
		var timer;
		me.addListener("ready", function() {
			var me = this;
			domUtils.on(me.body, "keyup", function(evt) {
				var code = evt.keyCode || evt.which,
					ignores = {
						16: 1,
						18: 1,
						20: 1,
						37: 1,
						38: 1,
						39: 1,
						40: 1
					};
				if (code in ignores) return;
				clearTimeout(timer);
				timer = setTimeout(function() {
					me.fireEvent("wordcount")
				}, 200)
			})
		})
	};
	UE.plugins["pagebreak"] = function() {
		var me = this,
			notBreakTags = ["td"];
		me.setOpt("pageBreakTag", "_ueditor_page_break_tag_");

		function fillNode(node) {
			if (domUtils.isEmptyBlock(node)) {
				var firstChild = node.firstChild,
					tmpNode;
				while (firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)) {
					tmpNode = firstChild;
					firstChild = firstChild.firstChild
				}!tmpNode && (tmpNode = node);
				domUtils.fillNode(me.document, tmpNode)
			}
		}
		me.ready(function() {
			utils.cssRule("pagebreak",
				".pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}",
				me.document)
		});

		function isHr(node) {
			return node && node.nodeType == 1 && node.tagName == "HR" && node.className == "pagebreak"
		}
		me.addInputRule(function(root) {
			root.traversal(function(node) {
				if (node.type == "text" && node.data == me.options.pageBreakTag) {
					var hr = UE.uNode.createElement(
						'<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;">'
						);
					node.parentNode.insertBefore(hr, node);
					node.parentNode.removeChild(node)
				}
			})
		});
		me.addOutputRule(function(node) {
			utils.each(node.getNodesByTagName("hr"), function(n) {
				if (n.getAttr("class") == "pagebreak") {
					var txt = UE.uNode.createText(me.options.pageBreakTag);
					n.parentNode.insertBefore(txt, n);
					n.parentNode.removeChild(n)
				}
			})
		});
		me.commands["pagebreak"] = {
			execCommand: function() {
				var range = me.selection.getRange(),
					hr = me.document.createElement("hr");
				domUtils.setAttributes(hr, {
					class: "pagebreak",
					noshade: "noshade",
					size: "5"
				});
				domUtils.unSelectable(hr);
				var node = domUtils.findParentByTagName(range.startContainer, notBreakTags, true),
					parents = [],
					pN;
				if (node) {
					switch (node.tagName) {
						case "TD":
							pN = node.parentNode;
							if (!pN.previousSibling) {
								var table = domUtils.findParentByTagName(pN, "table");
								table.parentNode.insertBefore(hr, table);
								parents = domUtils.findParents(hr, true)
							} else {
								pN.parentNode.insertBefore(hr, pN);
								parents = domUtils.findParents(hr)
							}
							pN = parents[1];
							if (hr !== pN) {
								domUtils.breakParent(hr, pN)
							}
							me.fireEvent("afteradjusttable", me.document)
					}
				} else {
					if (!range.collapsed) {
						range.deleteContents();
						var start = range.startContainer;
						while (!domUtils.isBody(start) && domUtils.isBlockElm(start) && domUtils
							.isEmptyNode(start)) {
							range.setStartBefore(start).collapse(true);
							domUtils.remove(start);
							start = range.startContainer
						}
					}
					range.insertNode(hr);
					var pN = hr.parentNode,
						nextNode;
					while (!domUtils.isBody(pN)) {
						domUtils.breakParent(hr, pN);
						nextNode = hr.nextSibling;
						if (nextNode && domUtils.isEmptyBlock(nextNode)) {
							domUtils.remove(nextNode)
						}
						pN = hr.parentNode
					}
					nextNode = hr.nextSibling;
					var pre = hr.previousSibling;
					if (isHr(pre)) {
						domUtils.remove(pre)
					} else {
						pre && fillNode(pre)
					}
					if (!nextNode) {
						var p = me.document.createElement("p");
						hr.parentNode.appendChild(p);
						domUtils.fillNode(me.document, p);
						range.setStart(p, 0).collapse(true)
					} else {
						if (isHr(nextNode)) {
							domUtils.remove(nextNode)
						} else {
							fillNode(nextNode)
						}
						range.setEndAfter(hr).collapse(false)
					}
					range.select(true)
				}
			}
		}
	};
	UE.plugin.register("wordimage", function() {
		var me = this,
			images = [];
		this.addListener("click", function(type, evt) {
			var el = evt.target || evt.srcElement;
			if ("IMG" == el.tagName && el.getAttribute("data-word-image")) {
				me.ui._dialogs.wordimageDialog && me.ui._dialogs.wordimageDialog.open()
			}
		});
		return {
			commands: {
				wordimage: {
					execCommand: function() {
						var images = domUtils.getElementsByTagName(me.body, "img");
						var urlList = [];
						for (var i = 0, ci; ci = images[i++];) {
							var url = ci.getAttribute("data-word-image");
							url && urlList.push(url)
						}
						return urlList
					},
					queryCommandState: function() {
						images = domUtils.getElementsByTagName(me.body, "img");
						for (var i = 0, ci; ci = images[i++];) {
							if (ci.getAttribute("data-word-image")) {
								return 1
							}
						}
						return -1
					},
					notNeedUndo: true
				}
			},
			inputRule: function(root) {
				utils.each(root.getNodesByTagName("img"), function(img) {
					var attrs = img.attrs,
						flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
						opt = me.options,
						src = opt.UEDITOR_HOME_URL + "themes/default/images/spacer.gif";
					if (attrs["src"] && /^(?:(file:\/+))/.test(attrs["src"])) {
						img.setAttr({
							width: attrs.width,
							height: attrs.height,
							alt: attrs.alt,
							"data-word-image": attrs.src,
							src: src,
							style: "background:url(" + (flag ? opt.themePath + opt
									.theme + "/images/word.gif" : opt.langPath + opt
									.lang + "/images/localimage.png") +
								") no-repeat center center;border:1px solid #ddd"
						})
					}
				})
			}
		}
	});
	UE.plugin.register("autosave", function() {
		var me = this,
			saveKey = null;

		function save(editor) {
			var saveData;
			if (!editor.hasContents()) {
				saveKey && me.removePreferences(saveKey);
				return
			}
			editor._autoSaveTimer = null;
			saveData = me.body.innerHTML;
			if (editor.fireEvent("beforeautosave", {
					content: saveData
				}) === false) {
				return
			}
			me.setPreferences(saveKey, saveData);
			editor.fireEvent("afterautosave", {
				content: saveData
			})
		}
		return {
			defaultOptions: {
				autoSaveEnable: true,
				autoSaveRestore: false,
				autoSaveKey: null
			},
			bindEvents: {
				ready: function() {
					saveKey = me.getOpt("autoSaveKey");
					if (!saveKey) {
						var _suffix = "_DraftsData",
							key = null;
						if (me.key) {
							key = me.key + _suffix
						} else {
							key = (me.container.parentNode.id || "ue-common") + _suffix
						}
						saveKey = (location.protocol + location.host + location.pathname).replace(
							/[.:\/]/g, "_") + key
					}
					if (me.getOpt("autoSaveRestore")) {
						var data = me.getPreferences(saveKey);
						if (data) {
							me.body.innerHTML = data;
							me.fireEvent("showmessage", {
								type: "info",
								content: me.getLang("autosave").autoRestoreTip
							})
						}
					}
				},
				beforesubmit: function() {
					if (!me.getOpt("autoSaveEnable") || !saveKey) {
						return
					}
					me.execCommand("clear_auto_save_content")
				},
				contentchange: function() {
					if (!me.isReady) {
						return
					}
					if (!me.getOpt("autoSaveEnable") || !saveKey) {
						return
					}
					if (me._autoSaveTimer) {
						window.clearTimeout(me._autoSaveTimer)
					}
					me._autoSaveTimer = window.setTimeout(function() {
						save(me)
					}, 1e3)
				}
			},
			commands: {
				clear_auto_save_content: {
					execCommand: function(cmd, name) {
						if (saveKey && me.getPreferences(saveKey)) {
							me.removePreferences(saveKey)
						}
					},
					notNeedUndo: true,
					ignoreContentChange: true
				},
				set_auto_save_content: {
					execCommand: function(cmd, name) {
						save(me)
					},
					notNeedUndo: true,
					ignoreContentChange: true
				},
				get_auto_save_content: {
					execCommand: function(cmd, name) {
						return me.getPreferences(saveKey) || ""
					},
					notNeedUndo: true,
					ignoreContentChange: true
				},
				auto_save_restore: {
					execCommand: function(cmd, name) {
						if (saveKey) {
							me.body.innerHTML = me.getPreferences(saveKey) || "<p>" + domUtils
								.fillHtml + "</p>";
							me.focus(true)
						}
					},
					queryCommandState: function() {
						return saveKey ? me.getPreferences(saveKey) === null ? -1 : 0 : -1
					},
					notNeedUndo: true,
					ignoreContentChange: true
				}
			}
		}
	});
	UE.plugin.register("formula", function() {
		var me = this,
			images = [];
		return {
			commands: {
				formula: {
					execCommand: function(cmdName, value) {
						var range = me.selection.getRange(),
							img = range.getClosedNode();
						value = encodeURIComponent(value);
						var formulaConfig = me.getOpt("formulaConfig");
						var src = formulaConfig.imageUrlTemplate.replace(/\{\}/, value);
						if (img) {
							img.setAttribute("src", src)
						} else {
							me.execCommand("insertHtml", '<img src="' + src + '" data-formula-image="' +
								value + '" />')
						}
					}
				}
			}
		}
	});
	UE.plugins["dragdrop"] = function() {
		var me = this;
		me.ready(function() {
			domUtils.on(this.body, "dragend", function() {
				var rng = me.selection.getRange();
				var node = rng.getClosedNode() || me.selection.getStart();
				if (node && node.tagName == "IMG") {
					var pre = node.previousSibling,
						next;
					while (next = node.nextSibling) {
						if (next.nodeType == 1 && next.tagName == "SPAN" && !next.firstChild) {
							domUtils.remove(next)
						} else {
							break
						}
					}
					if ((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre) || !pre) && (!
							next || next && !domUtils.isEmptyBlock(next))) {
						if (pre && pre.tagName == "P" && !domUtils.isEmptyBlock(pre)) {
							pre.appendChild(node);
							domUtils.moveChild(next, pre);
							domUtils.remove(next)
						} else if (next && next.tagName == "P" && !domUtils.isEmptyBlock(
							next)) {
							next.insertBefore(node, next.firstChild)
						}
						if (pre && pre.tagName == "P" && domUtils.isEmptyBlock(pre)) {
							domUtils.remove(pre)
						}
						if (next && next.tagName == "P" && domUtils.isEmptyBlock(next)) {
							domUtils.remove(next)
						}
						rng.selectNode(node).select();
						me.fireEvent("saveScene")
					}
				}
			})
		});
		me.addListener("keyup", function(type, evt) {
			var keyCode = evt.keyCode || evt.which;
			if (keyCode == 13) {
				var rng = me.selection.getRange(),
					node;
				if (node = domUtils.findParentByTagName(rng.startContainer, "p", true)) {
					if (domUtils.getComputedStyle(node, "text-align") == "center") {
						domUtils.removeStyle(node, "text-align")
					}
				}
			}
		})
	};
	UE.plugins["undo"] = function() {
		var saveSceneTimer;
		var me = this,
			maxUndoCount = me.options.maxUndoCount || 20,
			maxInputCount = me.options.maxInputCount || 20,
			fillchar = new RegExp(domUtils.fillChar + "|</hr>", "gi");
		var noNeedFillCharTags = {
			ol: 1,
			ul: 1,
			table: 1,
			tbody: 1,
			tr: 1,
			body: 1
		};
		var orgState = me.options.autoClearEmptyNode;

		function compareAddr(indexA, indexB) {
			if (indexA.length != indexB.length) return 0;
			for (var i = 0, l = indexA.length; i < l; i++) {
				if (indexA[i] != indexB[i]) return 0
			}
			return 1
		}

		function compareRangeAddress(rngAddrA, rngAddrB) {
			if (rngAddrA.collapsed != rngAddrB.collapsed) {
				return 0
			}
			if (!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress,
					rngAddrB.endAddress)) {
				return 0
			}
			return 1
		}

		function UndoManager() {
			this.list = [];
			this.index = 0;
			this.hasUndo = false;
			this.hasRedo = false;
			this.undo = function() {
				if (this.hasUndo) {
					if (!this.list[this.index - 1] && this.list.length == 1) {
						this.reset();
						return
					}
					while (this.list[this.index].content == this.list[this.index - 1].content) {
						this.index--;
						if (this.index == 0) {
							return this.restore(0)
						}
					}
					this.restore(--this.index)
				}
			};
			this.redo = function() {
				if (this.hasRedo) {
					while (this.list[this.index].content == this.list[this.index + 1].content) {
						this.index++;
						if (this.index == this.list.length - 1) {
							return this.restore(this.index)
						}
					}
					this.restore(++this.index)
				}
			};
			this.restore = function() {
				var me = this.editor;
				var scene = this.list[this.index];
				var root = UE.htmlparser(scene.content.replace(fillchar, ""));
				me.options.autoClearEmptyNode = false;
				me.filterInputRule(root);
				me.options.autoClearEmptyNode = orgState;
				me.document.body.innerHTML = root.toHtml();
				me.fireEvent("afterscencerestore");
				if (browser.ie) {
					utils.each(domUtils.getElementsByTagName(me.document, "td th caption p"), function(
					node) {
						if (domUtils.isEmptyNode(node)) {
							domUtils.fillNode(me.document, node)
						}
					})
				}
				try {
					var rng = new dom.Range(me.document).moveToAddress(scene.address);
					rng.select(noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()])
				} catch (e) {}
				this.update();
				this.clearKey();
				me.fireEvent("reset", true)
			};
			this.getScene = function() {
				var me = this.editor;
				var rng = me.selection.getRange(),
					rngAddress = rng.createAddress(false, true);
				me.fireEvent("beforegetscene");
				var root = UE.htmlparser(me.body.innerHTML);
				me.options.autoClearEmptyNode = false;
				me.filterOutputRule(root);
				me.options.autoClearEmptyNode = orgState;
				var cont = root.toHtml();
				me.fireEvent("aftergetscene");
				return {
					address: rngAddress,
					content: cont
				}
			};
			this.save = function(notCompareRange, notSetCursor) {
				clearTimeout(saveSceneTimer);
				var currentScene = this.getScene(notSetCursor),
					lastScene = this.list[this.index];
				if (!lastScene || lastScene && lastScene.content != currentScene.content) {
					setTimeout(function() {
						me.trigger("contentchange")
					}, 0)
				}
				if (lastScene && lastScene.content == currentScene.content && (notCompareRange ? 1 :
						compareRangeAddress(lastScene.address, currentScene.address))) {
					return
				}
				this.list = this.list.slice(0, this.index + 1);
				this.list.push(currentScene);
				if (this.list.length > maxUndoCount) {
					this.list.shift()
				}
				this.index = this.list.length - 1;
				this.clearKey();
				this.update()
			};
			this.update = function() {
				this.hasRedo = !!this.list[this.index + 1];
				this.hasUndo = !!this.list[this.index - 1]
			};
			this.reset = function() {
				this.list = [];
				this.index = 0;
				this.hasUndo = false;
				this.hasRedo = false;
				this.clearKey()
			};
			this.clearKey = function() {
				keycont = 0;
				lastKeyCode = null
			}
		}
		me.undoManger = new UndoManager;
		me.undoManger.editor = me;

		function saveScene() {
			this.undoManger.save()
		}
		me.addListener("saveScene", function() {
			var args = Array.prototype.splice.call(arguments, 1);
			this.undoManger.save.apply(this.undoManger, args)
		});
		me.addListener("reset", function(type, exclude) {
			if (!exclude) {
				this.undoManger.reset()
			}
		});
		me.commands["redo"] = me.commands["undo"] = {
			execCommand: function(cmdName) {
				this.undoManger[cmdName]()
			},
			queryCommandState: function(cmdName) {
				return this.undoManger["has" + (cmdName.toLowerCase() == "undo" ? "Undo" : "Redo")] ?
					0 : -1
			},
			notNeedUndo: 1
		};
		var keys = {
				16: 1,
				17: 1,
				18: 1,
				37: 1,
				38: 1,
				39: 1,
				40: 1
			},
			keycont = 0,
			lastKeyCode;
		var inputType = false;
		me.addListener("ready", function() {
			domUtils.on(this.body, "compositionstart", function() {
				inputType = true
			});
			domUtils.on(this.body, "compositionend", function() {
				inputType = false
			})
		});
		me.addshortcutkey({
			Undo: "ctrl+90",
			Redo: "ctrl+89"
		});
		var isCollapsed = true;
		me.addListener("keyup", function(type, evt) {
			var me = this;
			var keyCode = evt.keyCode || evt.which;
			if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
				if (inputType) return;
				if (!me.selection.getRange().collapsed) {
					me.undoManger.save(false, true);
					isCollapsed = false;
					return
				}
				if (me.undoManger.list.length === 0) {
					me.undoManger.save(true)
				}
				clearTimeout(saveSceneTimer);

				function save(cont) {
					cont.undoManger.save(false, true);
					cont.fireEvent("selectionchange")
				}
				saveSceneTimer = setTimeout(function() {
					if (inputType) {
						var intervalTimer = setInterval(function() {
							if (!inputType) {
								save(me);
								clearInterval(intervalTimer)
							}
						}, 300);
						return
					}
					save(me)
				}, 200);
				lastKeyCode = keyCode;
				keycont++;
				if (keycont >= maxInputCount) {
					save(me)
				}
			}
		});
		me.addListener("keyup", function(type, evt) {
			var keyCode = evt.keyCode || evt.which;
			if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
				if (inputType) return;
				if (!isCollapsed) {
					this.undoManger.save(false, true);
					isCollapsed = true
				}
			}
		});
		me.stopCmdUndo = function() {
			me.__hasEnterExecCommand = true
		};
		me.startCmdUndo = function() {
			me.__hasEnterExecCommand = false
		}
	};
	UE.plugin.register("copy", function() {
		var me = this;

		function initZeroClipboard() {
			ZeroClipboard.config({
				debug: false,
				swfPath: me.options.UEDITOR_HOME_URL + "third-party/zeroclipboard/ZeroClipboard.swf"
			});
			var client = me.zeroclipboard = new ZeroClipboard;
			client.on("copy", function(e) {
				var client = e.client,
					rng = me.selection.getRange(),
					div = document.createElement("div");
				div.appendChild(rng.cloneContents());
				client.setText(div.innerText || div.textContent);
				client.setHtml(div.innerHTML);
				rng.select()
			});
			client.on("mouseover mouseout", function(e) {
				var target = e.target;
				if (target) {
					if (e.type == "mouseover") {
						domUtils.addClass(target, "edui-state-hover")
					} else if (e.type == "mouseout") {
						domUtils.removeClasses(target, "edui-state-hover")
					}
				}
			});
			client.on("wrongflash noflash", function() {
				ZeroClipboard.destroy()
			});
			me.fireEvent("zeroclipboardready", client)
		}
		return {
			bindEvents: {
				ready: function() {
					if (!browser.ie) {
						if (window.ZeroClipboard) {
							initZeroClipboard()
						} else {
							utils.loadFile(document, {
								src: me.options.UEDITOR_HOME_URL +
									"third-party/zeroclipboard/ZeroClipboard.js",
								tag: "script",
								type: "text/javascript",
								defer: "defer"
							}, function() {
								initZeroClipboard()
							})
						}
					}
				}
			},
			commands: {
				copy: {
					execCommand: function(cmd) {
						if (!me.document.execCommand("copy")) {
							alert(me.getLang("copymsg"))
						}
					}
				}
			}
		}
	});
	UE.plugins["paste"] = function() {
		function getClipboardData(callback) {
			var doc = this.document;
			if (doc.getElementById("baidu_pastebin")) {
				return
			}
			var range = this.selection.getRange(),
				bk = range.createBookmark(),
				pastebin = doc.createElement("div");
			pastebin.id = "baidu_pastebin";
			browser.webkit && pastebin.appendChild(doc.createTextNode(domUtils.fillChar + domUtils.fillChar));
			doc.body.appendChild(pastebin);
			bk.start.style.display = "";
			pastebin.style.cssText =
				"position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
				domUtils.getXY(bk.start).y + "px";
			range.selectNodeContents(pastebin).select(true);
			setTimeout(function() {
				if (browser.webkit) {
					for (var i = 0, pastebins = doc.querySelectorAll("#baidu_pastebin"), pi; pi =
						pastebins[i++];) {
						if (domUtils.isEmptyNode(pi)) {
							domUtils.remove(pi)
						} else {
							pastebin = pi;
							break
						}
					}
				}
				try {
					pastebin.parentNode.removeChild(pastebin)
				} catch (e) {}
				range.moveToBookmark(bk).select(true);
				callback(pastebin)
			}, 0)
		}
		var me = this;
		me.setOpt({
			retainOnlyLabelPasted: false
		});
		var txtContent, htmlContent, address;

		function getPureHtml(html) {
			return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function(a, b, tagName, attrs) {
				tagName = tagName.toLowerCase();
				if ({
						img: 1
					} [tagName]) {
					return a
				}
				attrs = attrs.replace(/([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi,
					function(str, atr, val) {
						if ({
								src: 1,
								href: 1,
								name: 1
							} [atr.toLowerCase()]) {
							return atr + "=" + val + " "
						}
						return ""
					});
				if ({
						span: 1,
						div: 1
					} [tagName]) {
					return ""
				} else {
					return "<" + b + tagName + " " + utils.trim(attrs) + ">"
				}
			})
		}

		function filter(div) {
			var html;
			if (div.firstChild) {
				var nodes = domUtils.getElementsByTagName(div, "span");
				for (var i = 0, ni; ni = nodes[i++];) {
					if (ni.id == "_baidu_cut_start" || ni.id == "_baidu_cut_end") {
						domUtils.remove(ni)
					}
				}
				if (browser.webkit) {
					var brs = div.querySelectorAll("div br");
					for (var i = 0, bi; bi = brs[i++];) {
						var pN = bi.parentNode;
						if (pN.tagName == "DIV" && pN.childNodes.length == 1) {
							pN.innerHTML = "<p><br/></p>";
							domUtils.remove(pN)
						}
					}
					var divs = div.querySelectorAll("#baidu_pastebin");
					for (var i = 0, di; di = divs[i++];) {
						var tmpP = me.document.createElement("p");
						di.parentNode.insertBefore(tmpP, di);
						while (di.firstChild) {
							tmpP.appendChild(di.firstChild)
						}
						domUtils.remove(di)
					}
					var metas = div.querySelectorAll("meta");
					for (var i = 0, ci; ci = metas[i++];) {
						domUtils.remove(ci)
					}
					var brs = div.querySelectorAll("br");
					for (i = 0; ci = brs[i++];) {
						if (/^apple-/i.test(ci.className)) {
							domUtils.remove(ci)
						}
					}
				}
				if (browser.gecko) {
					var dirtyNodes = div.querySelectorAll("[_moz_dirty]");
					for (i = 0; ci = dirtyNodes[i++];) {
						ci.removeAttribute("_moz_dirty")
					}
				}
				if (!browser.ie) {
					var spans = div.querySelectorAll("span.Apple-style-span");
					for (var i = 0, ci; ci = spans[i++];) {
						domUtils.remove(ci, true)
					}
				}
				html = div.innerHTML;
				html = UE.filterWord(html);
				var root = UE.htmlparser(html);
				if (me.options.filterRules) {
					UE.filterNode(root, me.options.filterRules)
				}
				me.filterInputRule(root);
				if (browser.webkit) {
					var br = root.lastChild();
					if (br && br.type == "element" && br.tagName == "br") {
						root.removeChild(br)
					}
					utils.each(me.body.querySelectorAll("div"), function(node) {
						if (domUtils.isEmptyBlock(node)) {
							domUtils.remove(node, true)
						}
					})
				}
				html = {
					html: root.toHtml()
				};
				me.fireEvent("beforepaste", html, root);
				if (!html.html) {
					return
				}
				root = UE.htmlparser(html.html, true);
				if (me.queryCommandState("pasteplain") === 1) {
					me.execCommand("insertHtml", UE.filterNode(root, me.options.filterTxtRules).toHtml(), true)
				} else {
					UE.filterNode(root, me.options.filterTxtRules);
					txtContent = root.toHtml();
					htmlContent = html.html;
					address = me.selection.getRange().createAddress(true);
					me.execCommand("insertHtml", me.getOpt("retainOnlyLabelPasted") === true ? getPureHtml(
						htmlContent) : htmlContent, true)
				}
				me.fireEvent("afterpaste", html)
			}
		}
		me.addListener("pasteTransfer", function(cmd, plainType) {
			if (address && txtContent && htmlContent && txtContent != htmlContent) {
				var range = me.selection.getRange();
				range.moveToAddress(address, true);
				if (!range.collapsed) {
					while (!domUtils.isBody(range.startContainer)) {
						var start = range.startContainer;
						if (start.nodeType == 1) {
							start = start.childNodes[range.startOffset];
							if (!start) {
								range.setStartBefore(range.startContainer);
								continue
							}
							var pre = start.previousSibling;
							if (pre && pre.nodeType == 3 && new RegExp("^[\n\r\t " + domUtils.fillChar +
									"]*$").test(pre.nodeValue)) {
								range.setStartBefore(pre)
							}
						}
						if (range.startOffset == 0) {
							range.setStartBefore(range.startContainer)
						} else {
							break
						}
					}
					while (!domUtils.isBody(range.endContainer)) {
						var end = range.endContainer;
						if (end.nodeType == 1) {
							end = end.childNodes[range.endOffset];
							if (!end) {
								range.setEndAfter(range.endContainer);
								continue
							}
							var next = end.nextSibling;
							if (next && next.nodeType == 3 && new RegExp("^[\n\r\t" + domUtils
									.fillChar + "]*$").test(next.nodeValue)) {
								range.setEndAfter(next)
							}
						}
						if (range.endOffset == range.endContainer[range.endContainer.nodeType == 3 ?
								"nodeValue" : "childNodes"].length) {
							range.setEndAfter(range.endContainer)
						} else {
							break
						}
					}
				}
				range.deleteContents();
				range.select(true);
				me.__hasEnterExecCommand = true;
				var html = htmlContent;
				if (plainType === 2) {
					html = getPureHtml(html)
				} else if (plainType) {
					html = txtContent
				}
				me.execCommand("inserthtml", html, true);
				me.__hasEnterExecCommand = false;
				var rng = me.selection.getRange();
				while (!domUtils.isBody(rng.startContainer) && !rng.startOffset && rng.startContainer[
						rng.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"].length) {
					rng.setStartBefore(rng.startContainer)
				}
				var tmpAddress = rng.createAddress(true);
				address.endAddress = tmpAddress.startAddress
			}
		});
		me.addListener("ready", function() {
			domUtils.on(me.body, "cut", function() {
				var range = me.selection.getRange();
				if (!range.collapsed && me.undoManger) {
					me.undoManger.save()
				}
			});
			domUtils.on(me.body, browser.ie || browser.opera ? "keydown" : "paste", function(e) {
				if ((browser.ie || browser.opera) && (!e.ctrlKey && !e.metaKey || e.keyCode !=
						"86")) {
					return
				}
				getClipboardData.call(me, function(div) {
					filter(div)
				})
			})
		});
		me.commands["paste"] = {
			execCommand: function(cmd) {
				if (browser.ie) {
					getClipboardData.call(me, function(div) {
						filter(div)
					});
					me.document.execCommand("paste")
				} else {
					alert(me.getLang("pastemsg"))
				}
			}
		}
	};
	UE.plugins["pasteplain"] = function() {
		var me = this;
		me.setOpt({
			pasteplain: false,
			filterTxtRules: function() {
				function transP(node) {
					node.tagName = "p";
					node.setStyle()
				}

				function removeNode(node) {
					node.parentNode.removeChild(node, true)
				}
				return {
					"-": "script style object iframe embed input select",
					p: {
						$: {}
					},
					br: {
						$: {}
					},
					div: function(node) {
						var tmpNode, p = UE.uNode.createElement("p");
						while (tmpNode = node.firstChild()) {
							if (tmpNode.type == "text" || !UE.dom.dtd.$block[tmpNode.tagName]) {
								p.appendChild(tmpNode)
							} else {
								if (p.firstChild()) {
									node.parentNode.insertBefore(p, node);
									p = UE.uNode.createElement("p")
								} else {
									node.parentNode.insertBefore(tmpNode, node)
								}
							}
						}
						if (p.firstChild()) {
							node.parentNode.insertBefore(p, node)
						}
						node.parentNode.removeChild(node)
					},
					ol: removeNode,
					ul: removeNode,
					dl: removeNode,
					dt: removeNode,
					dd: removeNode,
					li: removeNode,
					caption: transP,
					th: transP,
					tr: transP,
					h1: transP,
					h2: transP,
					h3: transP,
					h4: transP,
					h5: transP,
					h6: transP,
					td: function(node) {
						var txt = !!node.innerText();
						if (txt) {
							node.parentNode.insertAfter(UE.uNode.createText(" &nbsp; &nbsp;"),
								node)
						}
						node.parentNode.removeChild(node, node.innerText())
					}
				}
			}()
		});
		var pasteplain = me.options.pasteplain;
		me.commands["pasteplain"] = {
			queryCommandState: function() {
				return pasteplain ? 1 : 0
			},
			execCommand: function() {
				pasteplain = !pasteplain | 0
			},
			notNeedUndo: 1
		}
	};
	UE.plugins["list"] = function() {
		var me = this,
			notExchange = {
				TD: 1,
				PRE: 1,
				BLOCKQUOTE: 1
			};
		me.setOpt({
			autoTransWordToList: false,
			insertorderedlist: {
				decimal: "",
				"lower-alpha": "",
				"lower-roman": "",
				"upper-alpha": "",
				"upper-roman": ""
			},
			insertunorderedlist: {
				circle: "",
				disc: "",
				square: ""
			},
			listDefaultPaddingLeft: "30",
			listiconpath: "http://bs.baidu.com/listicon/",
			maxListLevel: -1,
			disablePInList: false
		});

		function listToArray(list) {
			var arr = [];
			for (var p in list) {
				arr.push(p)
			}
			return arr
		}
		var listStyle = {
			OL: listToArray(me.options.insertorderedlist),
			UL: listToArray(me.options.insertunorderedlist)
		};
		var liiconpath = me.options.listiconpath;
		me.ready(function() {
			var customCss = [];
			customCss.push(".list-paddingleft-1{padding-left:0}");
			customCss.push(".list-paddingleft-2{padding-left:" + me.options.listDefaultPaddingLeft +
				"px}");
			customCss.push(".list-paddingleft-3{padding-left:" + me.options.listDefaultPaddingLeft * 2 +
				"px}");
			utils.cssRule("list", "ol,ul{margin:0;pading:0;" + (browser.ie ? "" : "width:95%") +
				"}li{clear:both;}" + customCss.join("\n"), me.document)
		});
		me.ready(function() {
			domUtils.on(me.body, "cut", function() {
				setTimeout(function() {
					var rng = me.selection.getRange(),
						li;
					if (!rng.collapsed) {
						if (li = domUtils.findParentByTagName(rng.startContainer, "li",
								true)) {
							if (!li.nextSibling && domUtils.isEmptyBlock(li)) {
								var pn = li.parentNode,
									node;
								if (node = pn.previousSibling) {
									domUtils.remove(pn);
									rng.setStartAtLast(node).collapse(true);
									rng.select(true)
								} else if (node = pn.nextSibling) {
									domUtils.remove(pn);
									rng.setStartAtFirst(node).collapse(true);
									rng.select(true)
								} else {
									var tmpNode = me.document.createElement("p");
									domUtils.fillNode(me.document, tmpNode);
									pn.parentNode.insertBefore(tmpNode, pn);
									domUtils.remove(pn);
									rng.setStart(tmpNode, 0).collapse(true);
									rng.select(true)
								}
							}
						}
					}
				})
			})
		});

		function getStyle(node) {
			var cls = node.className;
			if (domUtils.hasClass(node, /custom_/)) {
				return cls.match(/custom_(\w+)/)[1]
			}
			return domUtils.getStyle(node, "list-style-type")
		}
		me.addListener("beforepaste", function(type, html) {
			var me = this,
				rng = me.selection.getRange(),
				li;
			var root = UE.htmlparser(html.html, true);
			if (li = domUtils.findParentByTagName(rng.startContainer, "li", true)) {
				var list = li.parentNode,
					tagName = list.tagName === "OL" ? "ul" : "ol";
				utils.each(root.getNodesByTagName(tagName), function(n) {
					n.tagName = list.tagName;
					n.setAttr();
					if (n.parentNode === root) {
						type = getStyle(list) || (list.tagName == "OL" ? "decimal" : "disc")
					} else {
						var className = n.parentNode.getAttr("class");
						if (className && /custom_/.test(className)) {
							type = className.match(/custom_(\w+)/)[1]
						} else {
							type = n.parentNode.getStyle("list-style-type")
						}
						if (!type) {
							type = list.tagName === "OL" ? "decimal" : "disc"
						}
					}
					var index = utils.indexOf(listStyle[list.tagName], type);
					if (n.parentNode !== root) index = index + 1 === listStyle[list.tagName]
						.length ? 0 : index + 1;
					var currentStyle = listStyle[list.tagName][index];
					n.setStyle("list-style-type", currentStyle)
				})
			}
			html.html = root.toHtml()
		});
		me.getOpt("disablePInList") === true && me.addOutputRule(function(root) {
			utils.each(root.getNodesByTagName("li"), function(li) {
				var newChildrens = [],
					index = 0;
				utils.each(li.children, function(n) {
					if (n.tagName == "p") {
						var tmpNode;
						while (tmpNode = n.children.pop()) {
							newChildrens.splice(index, 0, tmpNode);
							tmpNode.parentNode = li;
							lastNode = tmpNode
						}
						tmpNode = newChildrens[newChildrens.length - 1];
						if (!tmpNode || tmpNode.type !== "element" || tmpNode
							.tagName !== "br") {
							var br = UE.uNode.createElement("br");
							br.parentNode = li;
							newChildrens.push(br)
						}
						index = newChildrens.length
					}
				});
				if (newChildrens.length) {
					li.children = newChildrens
				}
			})
		});
		me.addInputRule(function(root) {
			utils.each(root.getNodesByTagName("li"), function(li) {
				var tmpP = UE.uNode.createElement("p");
				for (var i = 0, ci; ci = li.children[i];) {
					if (ci.type === "text" || dtd.p[ci.tagName]) {
						tmpP.appendChild(ci)
					} else {
						if (tmpP.firstChild()) {
							li.insertBefore(tmpP, ci);
							tmpP = UE.uNode.createElement("p");
							i = i + 2
						} else {
							i++
						}
					}
				}
				if (tmpP.firstChild() && !tmpP.parentNode || !li.firstChild()) {
					li.appendChild(tmpP)
				}
				if (!tmpP.firstChild()) {
					tmpP.innerHTML(browser.ie ? "&nbsp;" : "<br/>")
				}
				var p = li.firstChild();
				var lastChild = p.lastChild();
				if (lastChild && lastChild.type === "text" && /^\s*$/.test(lastChild.data)) {
					p.removeChild(lastChild)
				}
			});
			if (me.options.autoTransWordToList) {
				var orderlisttype = {
						num1: /^\d+\)/,
						decimal: /^\d+\./,
						"lower-alpha": /^[a-z]+\)/,
						"upper-alpha": /^[A-Z]+\./,
						cn: /^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
						cn2: /^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/
					},
					unorderlisttype = {
						square: "n"
					};

				function checkListType(content, container) {
					var span = container.firstChild();
					if (span && span.type === "element" && span.tagName === "span" && /Wingdings|Symbol/
						.test(span.getStyle("font-family"))) {
						for (var p in unorderlisttype) {
							if (unorderlisttype[p] == span.data) {
								return p
							}
						}
						return "disc"
					}
					for (var p in orderlisttype) {
						if (orderlisttype[p].test(content)) {
							return p
						}
					}
				}
				utils.each(root.getNodesByTagName("p"), function(node) {
					if (node.getAttr("class") !== "MsoListParagraph") {
						return
					}
					node.setStyle("margin", "");
					node.setStyle("margin-left", "");
					node.setAttr("class", "");

					function appendLi(list, p, type) {
						if (list.tagName === "ol") {
							if (browser.ie) {
								var first = p.firstChild();
								if (first.type === "element" && first.tagName === "span" &&
									orderlisttype[type].test(first.innerText())) {
									p.removeChild(first)
								}
							} else {
								p.innerHTML(p.innerHTML().replace(orderlisttype[type], ""))
							}
						} else {
							p.removeChild(p.firstChild())
						}
						var li = UE.uNode.createElement("li");
						li.appendChild(p);
						list.appendChild(li)
					}
					var tmp = node,
						type, cacheNode = node;
					if (node.parentNode.tagName !== "li" && (type = checkListType(node
							.innerText(), node))) {
						var list = UE.uNode.createElement(me.options.insertorderedlist
							.hasOwnProperty(type) ? "ol" : "ul");
						list.setStyle("list-style-type", type);
						while (node && node.parentNode.tagName !== "li" && checkListType(node
								.innerText(), node)) {
							tmp = node.nextSibling();
							if (!tmp) {
								node.parentNode.insertBefore(list, node)
							}
							appendLi(list, node, type);
							node = tmp
						}
						if (!list.parentNode && node && node.parentNode) {
							node.parentNode.insertBefore(list, node)
						}
					}
					var span = cacheNode.firstChild();
					if (span && span.type == "element" && span.tagName == "span" &&
						/^\s*(&nbsp;)+\s*$/.test(span.innerText())) {
						span.parentNode.removeChild(span)
					}
				})
			}
		});
		me.addListener("contentchange", function() {
			adjustListStyle(me.document)
		});

		function adjustListStyle(doc, ignore) {
			utils.each(domUtils.getElementsByTagName(doc, "ol ul"), function(node) {
				if (!domUtils.inDoc(node, doc)) return;
				var parent = node.parentNode;
				if (parent.tagName === node.tagName) {
					var nodeStyleType = getStyle(node) || (node.tagName === "OL" ? "decimal" : "disc"),
						parentStyleType = getStyle(parent) || (parent.tagName === "OL" ? "decimal" :
							"disc");
					if (nodeStyleType === parentStyleType) {
						var styleIndex = utils.indexOf(listStyle[node.tagName], nodeStyleType);
						styleIndex = styleIndex + 1 === listStyle[node.tagName].length ? 0 :
							styleIndex + 1;
						setListStyle(node, listStyle[node.tagName][styleIndex])
					}
				}
				var index = 0,
					type = 2;
				if (domUtils.hasClass(node, /custom_/)) {
					if (!(/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent, /custom_/))) {
						type = 1
					}
				} else {
					if (/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent, /custom_/)) {
						type = 3
					}
				}
				var style = domUtils.getStyle(node, "list-style-type");
				style && (node.style.cssText = "list-style-type:" + style);
				node.className = utils.trim(node.className.replace(/list-paddingleft-\w+/, "")) +
					" list-paddingleft-" + type;
				utils.each(domUtils.getElementsByTagName(node, "li"), function(li) {
					li.style.cssText && (li.style.cssText = "");
					if (!li.firstChild) {
						domUtils.remove(li);
						return
					}
					if (li.parentNode !== node) {
						return
					}
					index++;
					if (domUtils.hasClass(node, /custom_/)) {
						var paddingLeft = 1,
							currentStyle = getStyle(node);
						if (node.tagName === "OL") {
							if (currentStyle) {
								switch (currentStyle) {
									case "cn":
									case "cn1":
									case "cn2":
										if (index > 10 && (index % 10 === 0 || index > 10 &&
												index < 20)) {
											paddingLeft = 2
										} else if (index > 20) {
											paddingLeft = 3
										}
										break;
									case "num2":
										if (index > 9) {
											paddingLeft = 2
										}
								}
							}
							li.className = "list-" + currentStyle + "-paddingleft-" +
								paddingLeft
						} else {
							li.className = "list-" + currentStyle + "-paddingleft"
						}
					} else {
						li.className = li.className.replace(/list-[\w\-]+/gi, "")
					}
					var className = li.getAttribute("class");
					if (className !== null && !className.replace(/\s/g, "")) {
						domUtils.removeAttributes(li, "class")
					}
				});
				!ignore && adjustList(node, node.tagName.toLowerCase(), getStyle(node) || domUtils
					.getStyle(node, "list-style-type"), true)
			})
		}

		function adjustList(list, tag, style, ignoreEmpty) {
			var nextList = list.nextSibling;
			if (nextList && nextList.nodeType === 1 && nextList.tagName.toLowerCase() === tag && (getStyle(
					nextList) || domUtils.getStyle(nextList, "list-style-type") || (tag == "ol" ?
					"decimal" : "disc")) == style) {
				domUtils.moveChild(nextList, list);
				if (nextList.childNodes.length === 0) {
					domUtils.remove(nextList)
				}
			}
			if (nextList && domUtils.isFillChar(nextList)) {
				domUtils.remove(nextList)
			}
			var preList = list.previousSibling;
			if (preList && preList.nodeType === 1 && preList.tagName.toLowerCase() == tag && (getStyle(
					preList) || domUtils.getStyle(preList, "list-style-type") || (tag == "ol" ? "decimal" :
						"disc")) === style) {
				domUtils.moveChild(list, preList)
			}
			if (preList && domUtils.isFillChar(preList)) {
				domUtils.remove(preList)
			}!ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list);
			if (getStyle(list)) {
				adjustListStyle(list.ownerDocument, true)
			}
		}

		function setListStyle(list, style) {
			try {
				domUtils.setStyle(list, "list-style-type", style)
			} catch (e) {}
		}

		function clearEmptySibling(node) {
			var tmpNode = node.previousSibling;
			if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
				domUtils.remove(tmpNode)
			}
			tmpNode = node.nextSibling;
			if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
				domUtils.remove(tmpNode)
			}
		}
		me.addListener("keydown", function(type, evt) {
			function preventAndSave() {
				evt.preventDefault ? evt.preventDefault() : evt.returnValue = false;
				me.fireEvent("contentchange");
				me.undoManger && me.undoManger.save()
			}

			function findList(node, filterFn) {
				while (node && !domUtils.isBody(node)) {
					if (filterFn(node)) {
						return null
					}
					if (node.nodeType === 1 && /[ou]l/i.test(node.tagName)) {
						return node
					}
					node = node.parentNode
				}
				return null
			}
			var keyCode = evt.keyCode || evt.which;
			if (keyCode === 13 && !evt.shiftKey) {
				var rng = me.selection.getRange(),
					parent = domUtils.findParent(rng.startContainer, function(node) {
						return domUtils.isBlockElm(node)
					}, true),
					li = domUtils.findParentByTagName(rng.startContainer, "li", true);
				if (parent && parent.tagName !== "PRE" && !li) {
					var html = parent.innerHTML.replace(new RegExp(domUtils.fillChar, "g"), "");
					if (/^\s*1\s*\.[^\d]/.test(html)) {
						parent.innerHTML = html.replace(/^\s*1\s*\./, "");
						rng.setStartAtLast(parent).collapse(true).select();
						me.__hasEnterExecCommand = true;
						me.execCommand("insertorderedlist");
						me.__hasEnterExecCommand = false
					}
				}
				var range = me.selection.getRange(),
					start = findList(range.startContainer, function(node) {
						return node.tagName === "TABLE"
					}),
					end = range.collapsed ? start : findList(range.endContainer, function(node) {
						return node.tagName === "TABLE"
					});
				if (start && end && start === end) {
					if (!range.collapsed) {
						start = domUtils.findParentByTagName(range.startContainer, "li", true);
						end = domUtils.findParentByTagName(range.endContainer, "li", true);
						if (start && end && start === end) {
							range.deleteContents();
							li = domUtils.findParentByTagName(range.startContainer, "li", true);
							if (li && domUtils.isEmptyBlock(li)) {
								pre = li.previousSibling;
								next = li.nextSibling;
								p = me.document.createElement("p");
								domUtils.fillNode(me.document, p);
								parentList = li.parentNode;
								if (pre && next) {
									range.setStart(next, 0).collapse(true).select(true);
									domUtils.remove(li)
								} else {
									if (!pre && !next || !pre) {
										parentList.parentNode.insertBefore(p, parentList)
									} else {
										li.parentNode.parentNode.insertBefore(p, parentList.nextSibling)
									}
									domUtils.remove(li);
									if (!parentList.firstChild) {
										domUtils.remove(parentList)
									}
									range.setStart(p, 0).setCursor()
								}
								preventAndSave();
								return
							}
						} else {
							var tmpRange = range.cloneRange(),
								bk = tmpRange.collapse(false).createBookmark();
							range.deleteContents();
							tmpRange.moveToBookmark(bk);
							var li = domUtils.findParentByTagName(tmpRange.startContainer, "li", true);
							clearEmptySibling(li);
							tmpRange.select();
							preventAndSave();
							return
						}
					}
					li = domUtils.findParentByTagName(range.startContainer, "li", true);
					if (li) {
						if (domUtils.isEmptyBlock(li)) {
							bk = range.createBookmark();
							var parentList = li.parentNode;
							if (li !== parentList.lastChild) {
								domUtils.breakParent(li, parentList);
								clearEmptySibling(li)
							} else {
								parentList.parentNode.insertBefore(li, parentList.nextSibling);
								if (domUtils.isEmptyNode(parentList)) {
									domUtils.remove(parentList)
								}
							}
							if (!dtd.$list[li.parentNode.tagName]) {
								if (!domUtils.isBlockElm(li.firstChild)) {
									p = me.document.createElement("p");
									li.parentNode.insertBefore(p, li);
									while (li.firstChild) {
										p.appendChild(li.firstChild)
									}
									domUtils.remove(li)
								} else {
									domUtils.remove(li, true)
								}
							}
							range.moveToBookmark(bk).select()
						} else {
							var first = li.firstChild;
							if (!first || !domUtils.isBlockElm(first)) {
								var p = me.document.createElement("p");
								!li.firstChild && domUtils.fillNode(me.document, p);
								while (li.firstChild) {
									p.appendChild(li.firstChild)
								}
								li.appendChild(p);
								first = p
							}
							var span = me.document.createElement("span");
							range.insertNode(span);
							domUtils.breakParent(span, li);
							var nextLi = span.nextSibling;
							first = nextLi.firstChild;
							if (!first) {
								p = me.document.createElement("p");
								domUtils.fillNode(me.document, p);
								nextLi.appendChild(p);
								first = p
							}
							if (domUtils.isEmptyNode(first)) {
								first.innerHTML = "";
								domUtils.fillNode(me.document, first)
							}
							range.setStart(first, 0).collapse(true).shrinkBoundary().select();
							domUtils.remove(span);
							var pre = nextLi.previousSibling;
							if (pre && domUtils.isEmptyBlock(pre)) {
								pre.innerHTML = "<p></p>";
								domUtils.fillNode(me.document, pre.firstChild)
							}
						}
						preventAndSave()
					}
				}
			}
			if (keyCode === 8) {
				range = me.selection.getRange();
				if (range.collapsed && domUtils.isStartInblock(range)) {
					tmpRange = range.cloneRange().trimBoundary();
					li = domUtils.findParentByTagName(range.startContainer, "li", true);
					if (li && domUtils.isStartInblock(tmpRange)) {
						start = domUtils.findParentByTagName(range.startContainer, "p", true);
						if (start && start !== li.firstChild) {
							var parentList = domUtils.findParentByTagName(start, ["ol", "ul"]);
							domUtils.breakParent(start, parentList);
							clearEmptySibling(start);
							me.fireEvent("contentchange");
							range.setStart(start, 0).setCursor(false, true);
							me.fireEvent("saveScene");
							domUtils.preventDefault(evt);
							return
						}
						if (li && (pre = li.previousSibling)) {
							if (keyCode === 46 && li.childNodes.length) {
								return
							}
							if (dtd.$list[pre.tagName]) {
								pre = pre.lastChild
							}
							me.undoManger && me.undoManger.save();
							first = li.firstChild;
							if (domUtils.isBlockElm(first)) {
								if (domUtils.isEmptyNode(first)) {
									pre.appendChild(first);
									range.setStart(first, 0).setCursor(false, true);
									while (li.firstChild) {
										pre.appendChild(li.firstChild)
									}
								} else {
									span = me.document.createElement("span");
									range.insertNode(span);
									if (domUtils.isEmptyBlock(pre)) {
										pre.innerHTML = ""
									}
									domUtils.moveChild(li, pre);
									range.setStartBefore(span).collapse(true).select(true);
									domUtils.remove(span)
								}
							} else {
								if (domUtils.isEmptyNode(li)) {
									var p = me.document.createElement("p");
									pre.appendChild(p);
									range.setStart(p, 0).setCursor()
								} else {
									range.setEnd(pre, pre.childNodes.length).collapse().select(true);
									while (li.firstChild) {
										pre.appendChild(li.firstChild)
									}
								}
							}
							domUtils.remove(li);
							me.fireEvent("contentchange");
							me.fireEvent("saveScene");
							domUtils.preventDefault(evt);
							return
						}
						if (li && !li.previousSibling) {
							var parentList = li.parentNode;
							var bk = range.createBookmark();
							if (domUtils.isTagNode(parentList.parentNode, "ol ul")) {
								parentList.parentNode.insertBefore(li, parentList);
								if (domUtils.isEmptyNode(parentList)) {
									domUtils.remove(parentList)
								}
							} else {
								while (li.firstChild) {
									parentList.parentNode.insertBefore(li.firstChild, parentList)
								}
								domUtils.remove(li);
								if (domUtils.isEmptyNode(parentList)) {
									domUtils.remove(parentList)
								}
							}
							range.moveToBookmark(bk).setCursor(false, true);
							me.fireEvent("contentchange");
							me.fireEvent("saveScene");
							domUtils.preventDefault(evt);
							return
						}
					}
				}
			}
		});
		me.addListener("keyup", function(type, evt) {
			var keyCode = evt.keyCode || evt.which;
			if (keyCode == 8) {
				var rng = me.selection.getRange(),
					list;
				if (list = domUtils.findParentByTagName(rng.startContainer, ["ol", "ul"], true)) {
					adjustList(list, list.tagName.toLowerCase(), getStyle(list) || domUtils
						.getComputedStyle(list, "list-style-type"), true)
				}
			}
		});
		me.addListener("tabkeydown", function() {
			var range = me.selection.getRange();

			function checkLevel(li) {
				if (me.options.maxListLevel != -1) {
					var level = li.parentNode,
						levelNum = 0;
					while (/[ou]l/i.test(level.tagName)) {
						levelNum++;
						level = level.parentNode
					}
					if (levelNum >= me.options.maxListLevel) {
						return true
					}
				}
			}
			var li = domUtils.findParentByTagName(range.startContainer, "li", true);
			if (li) {
				var bk;
				if (range.collapsed) {
					if (checkLevel(li)) return true;
					var parentLi = li.parentNode,
						list = me.document.createElement(parentLi.tagName),
						index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) || domUtils
							.getComputedStyle(parentLi, "list-style-type"));
					index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
					var currentStyle = listStyle[list.tagName][index];
					setListStyle(list, currentStyle);
					if (domUtils.isStartInblock(range)) {
						me.fireEvent("saveScene");
						bk = range.createBookmark();
						parentLi.insertBefore(list, li);
						list.appendChild(li);
						adjustList(list, list.tagName.toLowerCase(), currentStyle);
						me.fireEvent("contentchange");
						range.moveToBookmark(bk).select(true);
						return true
					}
				} else {
					me.fireEvent("saveScene");
					bk = range.createBookmark();
					for (var i = 0, closeList, parents = domUtils.findParents(li), ci; ci = parents[
						i++];) {
						if (domUtils.isTagNode(ci, "ol ul")) {
							closeList = ci;
							break
						}
					}
					var current = li;
					if (bk.end) {
						while (current && !(domUtils.getPosition(current, bk.end) & domUtils
								.POSITION_FOLLOWING)) {
							if (checkLevel(current)) {
								current = domUtils.getNextDomNode(current, false, null, function(node) {
									return node !== closeList
								});
								continue
							}
							var parentLi = current.parentNode,
								list = me.document.createElement(parentLi.tagName),
								index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) ||
									domUtils.getComputedStyle(parentLi, "list-style-type"));
							var currentIndex = index + 1 == listStyle[list.tagName].length ? 0 : index +
								1;
							var currentStyle = listStyle[list.tagName][currentIndex];
							setListStyle(list, currentStyle);
							parentLi.insertBefore(list, current);
							while (current && !(domUtils.getPosition(current, bk.end) & domUtils
									.POSITION_FOLLOWING)) {
								li = current.nextSibling;
								list.appendChild(current);
								if (!li || domUtils.isTagNode(li, "ol ul")) {
									if (li) {
										while (li = li.firstChild) {
											if (li.tagName == "LI") {
												break
											}
										}
									} else {
										li = domUtils.getNextDomNode(current, false, null, function(
											node) {
											return node !== closeList
										})
									}
									break
								}
								current = li
							}
							adjustList(list, list.tagName.toLowerCase(), currentStyle);
							current = li
						}
					}
					me.fireEvent("contentchange");
					range.moveToBookmark(bk).select();
					return true
				}
			}
		});

		function getLi(start) {
			while (start && !domUtils.isBody(start)) {
				if (start.nodeName == "TABLE") {
					return null
				}
				if (start.nodeName == "LI") {
					return start
				}
				start = start.parentNode
			}
		}
		me.commands["insertorderedlist"] = me.commands["insertunorderedlist"] = {
			execCommand: function(command, style) {
				if (!style) {
					style = command.toLowerCase() == "insertorderedlist" ? "decimal" : "disc"
				}
				var me = this,
					range = this.selection.getRange(),
					filterFn = function(node) {
						return node.nodeType == 1 ? node.tagName.toLowerCase() != "br" : !domUtils
							.isWhitespace(node)
					},
					tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul",
					frag = me.document.createDocumentFragment();
				range.adjustmentBoundary().shrinkBoundary();
				var bko = range.createBookmark(true),
					start = getLi(me.document.getElementById(bko.start)),
					modifyStart = 0,
					end = getLi(me.document.getElementById(bko.end)),
					modifyEnd = 0,
					startParent, endParent, list, tmp;
				if (start || end) {
					start && (startParent = start.parentNode);
					if (!bko.end) {
						end = start
					}
					end && (endParent = end.parentNode);
					if (startParent === endParent) {
						while (start !== end) {
							tmp = start;
							start = start.nextSibling;
							if (!domUtils.isBlockElm(tmp.firstChild)) {
								var p = me.document.createElement("p");
								while (tmp.firstChild) {
									p.appendChild(tmp.firstChild)
								}
								tmp.appendChild(p)
							}
							frag.appendChild(tmp)
						}
						tmp = me.document.createElement("span");
						startParent.insertBefore(tmp, end);
						if (!domUtils.isBlockElm(end.firstChild)) {
							p = me.document.createElement("p");
							while (end.firstChild) {
								p.appendChild(end.firstChild)
							}
							end.appendChild(p)
						}
						frag.appendChild(end);
						domUtils.breakParent(tmp, startParent);
						if (domUtils.isEmptyNode(tmp.previousSibling)) {
							domUtils.remove(tmp.previousSibling)
						}
						if (domUtils.isEmptyNode(tmp.nextSibling)) {
							domUtils.remove(tmp.nextSibling)
						}
						var nodeStyle = getStyle(startParent) || domUtils.getComputedStyle(startParent,
							"list-style-type") || (command.toLowerCase() == "insertorderedlist" ?
							"decimal" : "disc");
						if (startParent.tagName.toLowerCase() == tag && nodeStyle == style) {
							for (var i = 0, ci, tmpFrag = me.document.createDocumentFragment(); ci =
								frag.firstChild;) {
								if (domUtils.isTagNode(ci, "ol ul")) {
									tmpFrag.appendChild(ci)
								} else {
									while (ci.firstChild) {
										tmpFrag.appendChild(ci.firstChild);
										domUtils.remove(ci)
									}
								}
							}
							tmp.parentNode.insertBefore(tmpFrag, tmp)
						} else {
							list = me.document.createElement(tag);
							setListStyle(list, style);
							list.appendChild(frag);
							tmp.parentNode.insertBefore(list, tmp)
						}
						domUtils.remove(tmp);
						list && adjustList(list, tag, style);
						range.moveToBookmark(bko).select();
						return
					}
					if (start) {
						while (start) {
							tmp = start.nextSibling;
							if (domUtils.isTagNode(start, "ol ul")) {
								frag.appendChild(start)
							} else {
								var tmpfrag = me.document.createDocumentFragment(),
									hasBlock = 0;
								while (start.firstChild) {
									if (domUtils.isBlockElm(start.firstChild)) {
										hasBlock = 1
									}
									tmpfrag.appendChild(start.firstChild)
								}
								if (!hasBlock) {
									var tmpP = me.document.createElement("p");
									tmpP.appendChild(tmpfrag);
									frag.appendChild(tmpP)
								} else {
									frag.appendChild(tmpfrag)
								}
								domUtils.remove(start)
							}
							start = tmp
						}
						startParent.parentNode.insertBefore(frag, startParent.nextSibling);
						if (domUtils.isEmptyNode(startParent)) {
							range.setStartBefore(startParent);
							domUtils.remove(startParent)
						} else {
							range.setStartAfter(startParent)
						}
						modifyStart = 1
					}
					if (end && domUtils.inDoc(endParent, me.document)) {
						start = endParent.firstChild;
						while (start && start !== end) {
							tmp = start.nextSibling;
							if (domUtils.isTagNode(start, "ol ul")) {
								frag.appendChild(start)
							} else {
								tmpfrag = me.document.createDocumentFragment();
								hasBlock = 0;
								while (start.firstChild) {
									if (domUtils.isBlockElm(start.firstChild)) {
										hasBlock = 1
									}
									tmpfrag.appendChild(start.firstChild)
								}
								if (!hasBlock) {
									tmpP = me.document.createElement("p");
									tmpP.appendChild(tmpfrag);
									frag.appendChild(tmpP)
								} else {
									frag.appendChild(tmpfrag)
								}
								domUtils.remove(start)
							}
							start = tmp
						}
						var tmpDiv = domUtils.createElement(me.document, "div", {
							tmpDiv: 1
						});
						domUtils.moveChild(end, tmpDiv);
						frag.appendChild(tmpDiv);
						domUtils.remove(end);
						endParent.parentNode.insertBefore(frag, endParent);
						range.setEndBefore(endParent);
						if (domUtils.isEmptyNode(endParent)) {
							domUtils.remove(endParent)
						}
						modifyEnd = 1
					}
				}
				if (!modifyStart) {
					range.setStartBefore(me.document.getElementById(bko.start))
				}
				if (bko.end && !modifyEnd) {
					range.setEndAfter(me.document.getElementById(bko.end))
				}
				range.enlarge(true, function(node) {
					return notExchange[node.tagName]
				});
				frag = me.document.createDocumentFragment();
				var bk = range.createBookmark(),
					current = domUtils.getNextDomNode(bk.start, false, filterFn),
					tmpRange = range.cloneRange(),
					tmpNode, block = domUtils.isBlockElm;
				while (current && current !== bk.end && domUtils.getPosition(current, bk.end) & domUtils
					.POSITION_PRECEDING) {
					if (current.nodeType == 3 || dtd.li[current.tagName]) {
						if (current.nodeType == 1 && dtd.$list[current.tagName]) {
							while (current.firstChild) {
								frag.appendChild(current.firstChild)
							}
							tmpNode = domUtils.getNextDomNode(current, false, filterFn);
							domUtils.remove(current);
							current = tmpNode;
							continue
						}
						tmpNode = current;
						tmpRange.setStartBefore(current);
						while (current && current !== bk.end && (!block(current) || domUtils
								.isBookmarkNode(current))) {
							tmpNode = current;
							current = domUtils.getNextDomNode(current, false, null, function(node) {
								return !notExchange[node.tagName]
							})
						}
						if (current && block(current)) {
							tmp = domUtils.getNextDomNode(tmpNode, false, filterFn);
							if (tmp && domUtils.isBookmarkNode(tmp)) {
								current = domUtils.getNextDomNode(tmp, false, filterFn);
								tmpNode = tmp
							}
						}
						tmpRange.setEndAfter(tmpNode);
						current = domUtils.getNextDomNode(tmpNode, false, filterFn);
						var li = range.document.createElement("li");
						li.appendChild(tmpRange.extractContents());
						if (domUtils.isEmptyNode(li)) {
							var tmpNode = range.document.createElement("p");
							while (li.firstChild) {
								tmpNode.appendChild(li.firstChild)
							}
							li.appendChild(tmpNode)
						}
						frag.appendChild(li)
					} else {
						current = domUtils.getNextDomNode(current, true, filterFn)
					}
				}
				range.moveToBookmark(bk).collapse(true);
				list = me.document.createElement(tag);
				setListStyle(list, style);
				list.appendChild(frag);
				range.insertNode(list);
				adjustList(list, tag, style);
				for (var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, "div"); ci = tmpDivs[
						i++];) {
					if (ci.getAttribute("tmpDiv")) {
						domUtils.remove(ci, true)
					}
				}
				range.moveToBookmark(bko).select()
			},
			queryCommandState: function(command) {
				var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
				var path = this.selection.getStartElementPath();
				for (var i = 0, ci; ci = path[i++];) {
					if (ci.nodeName == "TABLE") {
						return 0
					}
					if (tag == ci.nodeName.toLowerCase()) {
						return 1
					}
				}
				return 0
			},
			queryCommandValue: function(command) {
				var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
				var path = this.selection.getStartElementPath(),
					node;
				for (var i = 0, ci; ci = path[i++];) {
					if (ci.nodeName == "TABLE") {
						node = null;
						break
					}
					if (tag == ci.nodeName.toLowerCase()) {
						node = ci;
						break
					}
				}
				return node ? getStyle(node) || domUtils.getComputedStyle(node, "list-style-type") :
					null
			}
		}
	};
	(function() {
		var sourceEditors = {
			textarea: function(editor, holder) {
				var textarea = holder.ownerDocument.createElement("textarea");
				textarea.style.cssText =
					"position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;";
				if (browser.ie && browser.version < 8) {
					textarea.style.width = holder.offsetWidth + "px";
					textarea.style.height = holder.offsetHeight + "px";
					holder.onresize = function() {
						textarea.style.width = holder.offsetWidth + "px";
						textarea.style.height = holder.offsetHeight + "px"
					}
				}
				holder.appendChild(textarea);
				return {
					setContent: function(content) {
						textarea.value = content
					},
					getContent: function() {
						return textarea.value
					},
					select: function() {
						var range;
						if (browser.ie) {
							range = textarea.createTextRange();
							range.collapse(true);
							range.select()
						} else {
							textarea.setSelectionRange(0, 0);
							textarea.focus()
						}
					},
					dispose: function() {
						holder.removeChild(textarea);
						holder.onresize = null;
						textarea = null;
						holder = null
					},
					focus: function() {
						textarea.focus()
					},
					blur: function() {
						textarea.blur()
					}
				}
			},
			codemirror: function(editor, holder) {
				var codeEditor = window.CodeMirror(holder, {
					mode: "text/html",
					tabMode: "indent",
					lineNumbers: true,
					lineWrapping: true,
					onChange: function(v) {
						editor.sync();
						editor.fireEvent("contentchange")
					}
				});
				var dom = codeEditor.getWrapperElement();
				dom.style.cssText =
					'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
				codeEditor.getScrollerElement().style.cssText =
					"position:absolute;left:0;top:0;width:100%;height:100%;";
				codeEditor.refresh();
				return {
					getCodeMirror: function() {
						return codeEditor
					},
					setContent: function(content) {
						codeEditor.setValue(content)
					},
					getContent: function() {
						return codeEditor.getValue()
					},
					select: function() {
						codeEditor.focus()
					},
					dispose: function() {
						holder.removeChild(dom);
						dom = null;
						codeEditor = null
					},
					focus: function() {
						codeEditor.focus()
					},
					blur: function() {
						codeEditor.setOption("readOnly", true);
						codeEditor.setOption("readOnly", false)
					}
				}
			}
		};
		UE.plugins["source"] = function() {
			var me = this;
			var opt = this.options;
			var sourceMode = false;
			var sourceEditor;
			var orgSetContent;
			var orgFocus;
			var orgBlur;
			opt.sourceEditor = browser.ie ? "textarea" : opt.sourceEditor || "codemirror";
			me.setOpt({
				sourceEditorFirst: false
			});

			function createSourceEditor(holder) {
				return sourceEditors[opt.sourceEditor == "codemirror" && window.CodeMirror ? "codemirror" :
					"textarea"](me, holder)
			}
			var bakCssText;
			var oldGetContent, bakAddress;
			me.commands["source"] = {
				execCommand: function() {
					sourceMode = !sourceMode;
					if (sourceMode) {
						bakAddress = me.selection.getRange().createAddress(false, true);
						me.undoManger && me.undoManger.save(true);
						if (browser.gecko) {
							me.body.contentEditable = false
						}
						bakCssText = me.iframe.style.cssText;
						me.iframe.style.cssText += "position:absolute;left:-32768px;top:-32768px;";
						me.fireEvent("beforegetcontent");
						var root = UE.htmlparser(me.body.innerHTML);
						me.filterOutputRule(root);
						root.traversal(function(node) {
							if (node.type == "element") {
								switch (node.tagName) {
									case "td":
									case "th":
									case "caption":
										if (node.children && node.children.length == 1) {
											if (node.firstChild().tagName == "br") {
												node.removeChild(node.firstChild())
											}
										}
										break;
									case "pre":
										node.innerText(node.innerText().replace(/&nbsp;/g,
											" "))
								}
							}
						});
						me.fireEvent("aftergetcontent");
						var content = root.toHtml(true);
						sourceEditor = createSourceEditor(me.iframe.parentNode);
						sourceEditor.setContent(content);
						orgSetContent = me.setContent;
						me.setContent = function(html) {
							var root = UE.htmlparser(html);
							me.filterInputRule(root);
							html = root.toHtml();
							sourceEditor.setContent(html)
						};
						setTimeout(function() {
							sourceEditor.select();
							me.addListener("fullscreenchanged", function() {
								try {
									sourceEditor.getCodeMirror().refresh()
								} catch (e) {}
							})
						});
						oldGetContent = me.getContent;
						me.getContent = function() {
							return sourceEditor.getContent() || "<p>" + (browser.ie ? "" :
								"<br/>") + "</p>"
						};
						orgFocus = me.focus;
						orgBlur = me.blur;
						me.focus = function() {
							sourceEditor.focus()
						};
						me.blur = function() {
							orgBlur.call(me);
							sourceEditor.blur()
						}
					} else {
						me.iframe.style.cssText = bakCssText;
						var cont = sourceEditor.getContent() || "<p>" + (browser.ie ? "" :
							"<br/>") + "</p>";
						cont = cont.replace(new RegExp("[\\r\\t\\n ]*</?(\\w+)\\s*(?:[^>]*)>", "g"),
							function(a, b) {
								if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
									return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, "")
								}
								return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, "")
							});
						me.setContent = orgSetContent;
						me.setContent(cont);
						sourceEditor.dispose();
						sourceEditor = null;
						me.getContent = oldGetContent;
						me.focus = orgFocus;
						me.blur = orgBlur;
						var first = me.body.firstChild;
						if (!first) {
							me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
							first = me.body.firstChild
						}
						me.undoManger && me.undoManger.save(true);
						if (browser.gecko) {
							var input = document.createElement("input");
							input.style.cssText = "position:absolute;left:0;top:-32768px";
							document.body.appendChild(input);
							me.body.contentEditable = false;
							setTimeout(function() {
								domUtils.setViewportOffset(input, {
									left: -32768,
									top: 0
								});
								input.focus();
								setTimeout(function() {
									me.body.contentEditable = true;
									me.selection.getRange().moveToAddress(
										bakAddress).select(true);
									domUtils.remove(input)
								})
							})
						} else {
							try {
								me.selection.getRange().moveToAddress(bakAddress).select(true)
							} catch (e) {}
						}
					}
					this.fireEvent("sourcemodechanged", sourceMode)
				},
				queryCommandState: function() {
					return sourceMode | 0
				},
				notNeedUndo: 1
			};
			var oldQueryCommandState = me.queryCommandState;
			me.queryCommandState = function(cmdName) {
				cmdName = cmdName.toLowerCase();
				if (sourceMode) {
					return cmdName in {
						source: 1,
						fullscreen: 1
					} ? 1 : -1
				}
				return oldQueryCommandState.apply(this, arguments)
			};
			if (opt.sourceEditor == "codemirror") {
				me.addListener("ready", function() {
					utils.loadFile(document, {
						src: opt.codeMirrorJsUrl || opt.UEDITOR_HOME_URL +
							"third-party/codemirror/codemirror.js",
						tag: "script",
						type: "text/javascript",
						defer: "defer"
					}, function() {
						if (opt.sourceEditorFirst) {
							setTimeout(function() {
								me.execCommand("source")
							}, 0)
						}
					});
					utils.loadFile(document, {
						tag: "link",
						rel: "stylesheet",
						type: "text/css",
						href: opt.codeMirrorCssUrl || opt.UEDITOR_HOME_URL +
							"third-party/codemirror/codemirror.css?221123"
					})
				})
			}
		}
	})();
	UE.plugins["enterkey"] = function() {
		var hTag, me = this,
			tag = me.options.enterTag;
		me.addListener("keyup", function(type, evt) {
			var keyCode = evt.keyCode || evt.which;
			if (keyCode == 13) {
				var range = me.selection.getRange(),
					start = range.startContainer,
					doSave;
				if (!browser.ie) {
					if (/h\d/i.test(hTag)) {
						if (browser.gecko) {
							var h = domUtils.findParentByTagName(start, ["h1", "h2", "h3", "h4", "h5",
								"h6", "blockquote", "caption", "table"
							], true);
							if (!h) {
								me.document.execCommand("formatBlock", false, "<p>");
								doSave = 1
							}
						} else {
							if (start.nodeType == 1) {
								var tmp = me.document.createTextNode(""),
									div;
								range.insertNode(tmp);
								div = domUtils.findParentByTagName(tmp, "div", true);
								if (div) {
									var p = me.document.createElement("p");
									while (div.firstChild) {
										p.appendChild(div.firstChild)
									}
									div.parentNode.insertBefore(p, div);
									domUtils.remove(div);
									range.setStartBefore(tmp).setCursor();
									doSave = 1
								}
								domUtils.remove(tmp)
							}
						}
						if (me.undoManger && doSave) {
							me.undoManger.save()
						}
					}
					browser.opera && range.select()
				} else {
					me.fireEvent("saveScene", true, true)
				}
			}
		});
		me.addListener("keydown", function(type, evt) {
			var keyCode = evt.keyCode || evt.which;
			if (keyCode == 13) {
				if (me.fireEvent("beforeenterkeydown")) {
					domUtils.preventDefault(evt);
					return
				}
				me.fireEvent("saveScene", true, true);
				hTag = "";
				var range = me.selection.getRange();
				if (!range.collapsed) {
					var start = range.startContainer,
						end = range.endContainer,
						startTd = domUtils.findParentByTagName(start, "td", true),
						endTd = domUtils.findParentByTagName(end, "td", true);
					if (startTd && endTd && startTd !== endTd || !startTd && endTd || startTd && !
						endTd) {
						evt.preventDefault ? evt.preventDefault() : evt.returnValue = false;
						return
					}
				}
				if (tag == "p") {
					if (!browser.ie) {
						start = domUtils.findParentByTagName(range.startContainer, ["ol", "ul", "p",
							"h1", "h2", "h3", "h4", "h5", "h6", "blockquote", "caption"
						], true);
						if (!start && !browser.opera) {
							me.document.execCommand("formatBlock", false, "<p>");
							if (browser.gecko) {
								range = me.selection.getRange();
								start = domUtils.findParentByTagName(range.startContainer, "p", true);
								start && domUtils.removeDirtyAttr(start)
							}
						} else {
							hTag = start.tagName;
							start.tagName.toLowerCase() == "p" && browser.gecko && domUtils
								.removeDirtyAttr(start)
						}
					}
				} else {
					evt.preventDefault ? evt.preventDefault() : evt.returnValue = false;
					if (!range.collapsed) {
						range.deleteContents();
						start = range.startContainer;
						if (start.nodeType == 1 && (start = start.childNodes[range.startOffset])) {
							while (start.nodeType == 1) {
								if (dtd.$empty[start.tagName]) {
									range.setStartBefore(start).setCursor();
									if (me.undoManger) {
										me.undoManger.save()
									}
									return false
								}
								if (!start.firstChild) {
									var br = range.document.createElement("br");
									start.appendChild(br);
									range.setStart(start, 0).setCursor();
									if (me.undoManger) {
										me.undoManger.save()
									}
									return false
								}
								start = start.firstChild
							}
							if (start === range.startContainer.childNodes[range.startOffset]) {
								br = range.document.createElement("br");
								range.insertNode(br).setCursor()
							} else {
								range.setStart(start, 0).setCursor()
							}
						} else {
							br = range.document.createElement("br");
							range.insertNode(br).setStartAfter(br).setCursor()
						}
					} else {
						br = range.document.createElement("br");
						range.insertNode(br);
						var parent = br.parentNode;
						if (parent.lastChild === br) {
							br.parentNode.insertBefore(br.cloneNode(true), br);
							range.setStartBefore(br)
						} else {
							range.setStartAfter(br)
						}
						range.setCursor()
					}
				}
			}
		})
	};
	UE.plugins["keystrokes"] = function() {
		var me = this;
		var collapsed = true;
		me.addListener("keydown", function(type, evt) {
			var keyCode = evt.keyCode || evt.which,
				rng = me.selection.getRange();
			if (!rng.collapsed && !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) && (
					keyCode >= 65 && keyCode <= 90 || keyCode >= 48 && keyCode <= 57 || keyCode >= 96 &&
					keyCode <= 111 || {
						13: 1,
						8: 1,
						46: 1
					} [keyCode])) {
				var tmpNode = rng.startContainer;
				if (domUtils.isFillChar(tmpNode)) {
					rng.setStartBefore(tmpNode)
				}
				tmpNode = rng.endContainer;
				if (domUtils.isFillChar(tmpNode)) {
					rng.setEndAfter(tmpNode)
				}
				rng.txtToElmBoundary();
				if (rng.endContainer && rng.endContainer.nodeType == 1) {
					tmpNode = rng.endContainer.childNodes[rng.endOffset];
					if (tmpNode && domUtils.isBr(tmpNode)) {
						rng.setEndAfter(tmpNode)
					}
				}
				if (rng.startOffset == 0) {
					tmpNode = rng.startContainer;
					if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
						tmpNode = rng.endContainer;
						if (rng.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode
								.childNodes.length) && domUtils.isBoundaryNode(tmpNode, "lastChild")) {
							me.fireEvent("saveScene");
							me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
							rng.setStart(me.body.firstChild, 0).setCursor(false, true);
							me._selectionChange();
							return
						}
					}
				}
			}
			if (keyCode == keymap.Backspace) {
				rng = me.selection.getRange();
				collapsed = rng.collapsed;
				if (me.fireEvent("delkeydown", evt)) {
					return
				}
				var start, end;
				if (rng.collapsed && rng.inFillChar()) {
					start = rng.startContainer;
					if (domUtils.isFillChar(start)) {
						rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
						domUtils.remove(start)
					} else {
						start.nodeValue = start.nodeValue.replace(new RegExp("^" + domUtils.fillChar),
							"");
						rng.startOffset--;
						rng.collapse(true).select(true)
					}
				}
				if (start = rng.getClosedNode()) {
					me.fireEvent("saveScene");
					rng.setStartBefore(start);
					domUtils.remove(start);
					rng.setCursor();
					me.fireEvent("saveScene");
					domUtils.preventDefault(evt);
					return
				}
				if (!browser.ie) {
					start = domUtils.findParentByTagName(rng.startContainer, "table", true);
					end = domUtils.findParentByTagName(rng.endContainer, "table", true);
					if (start && !end || !start && end || start !== end) {
						evt.preventDefault();
						return
					}
				}
			}
			if (keyCode == keymap.Tab) {
				var excludeTagNameForTabKey = {
					ol: 1,
					ul: 1,
					table: 1
				};
				if (me.fireEvent("tabkeydown", evt)) {
					domUtils.preventDefault(evt);
					return
				}
				var range = me.selection.getRange();
				me.fireEvent("saveScene");
				for (var i = 0, txt = "", tabSize = me.options.tabSize || 4, tabNode = me.options
						.tabNode || "&nbsp;"; i < tabSize; i++) {
					txt += tabNode
				}
				var span = me.document.createElement("span");
				span.innerHTML = txt + domUtils.fillChar;
				if (range.collapsed) {
					range.insertNode(span.cloneNode(true).firstChild).setCursor(true)
				} else {
					var filterFn = function(node) {
						return domUtils.isBlockElm(node) && !excludeTagNameForTabKey[node.tagName
							.toLowerCase()]
					};
					start = domUtils.findParent(range.startContainer, filterFn, true);
					end = domUtils.findParent(range.endContainer, filterFn, true);
					if (start && end && start === end) {
						range.deleteContents();
						range.insertNode(span.cloneNode(true).firstChild).setCursor(true)
					} else {
						var bookmark = range.createBookmark();
						range.enlarge(true);
						var bookmark2 = range.createBookmark(),
							current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
						while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils
								.POSITION_FOLLOWING)) {
							current.insertBefore(span.cloneNode(true).firstChild, current.firstChild);
							current = domUtils.getNextDomNode(current, false, filterFn)
						}
						range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select()
					}
				}
				domUtils.preventDefault(evt)
			}
			if (browser.gecko && keyCode == 46) {
				range = me.selection.getRange();
				if (range.collapsed) {
					start = range.startContainer;
					if (domUtils.isEmptyBlock(start)) {
						var parent = start.parentNode;
						while (domUtils.getChildCount(parent) == 1 && !domUtils.isBody(parent)) {
							start = parent;
							parent = parent.parentNode
						}
						if (start === parent.lastChild) evt.preventDefault();
						return
					}
				}
			}
			browser.chrome && me.on("keydown", function(type, e) {
				var keyCode = e.keyCode || e.which;
				if ((e.metaKey && e.altKey || e.ctrlKey && e.shiftKey) && keyCode == 73) {
					return true
				}
			})
		});
		me.addListener("keyup", function(type, evt) {
			var keyCode = evt.keyCode || evt.which,
				rng, me = this;
			if (keyCode == keymap.Backspace) {
				if (me.fireEvent("delkeyup")) {
					return
				}
				rng = me.selection.getRange();
				if (rng.collapsed) {
					var tmpNode, autoClearTagName = ["h1", "h2", "h3", "h4", "h5", "h6"];
					if (tmpNode = domUtils.findParentByTagName(rng.startContainer, autoClearTagName,
							true)) {
						if (domUtils.isEmptyBlock(tmpNode)) {
							var pre = tmpNode.previousSibling;
							if (pre && pre.nodeName != "TABLE") {
								domUtils.remove(tmpNode);
								rng.setStartAtLast(pre).setCursor(false, true);
								return
							} else {
								var next = tmpNode.nextSibling;
								if (next && next.nodeName != "TABLE") {
									domUtils.remove(tmpNode);
									rng.setStartAtFirst(next).setCursor(false, true);
									return
								}
							}
						}
					}
					if (domUtils.isBody(rng.startContainer)) {
						var tmpNode = domUtils.createElement(me.document, "p", {
							innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
						});
						rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true)
					}
				}
				if (!collapsed && (rng.startContainer.nodeType == 3 || rng.startContainer.nodeType ==
						1 && domUtils.isEmptyBlock(rng.startContainer))) {
					if (browser.ie) {
						var span = rng.document.createElement("span");
						rng.insertNode(span).setStartBefore(span).collapse(true);
						rng.select();
						domUtils.remove(span)
					} else {
						rng.select()
					}
				}
			}
		})
	};
	UE.plugins["fiximgclick"] = function() {
		var elementUpdated = false;

		function Scale() {
			this.editor = null;
			this.resizer = null;
			this.cover = null;
			this.doc = document;
			this.prePos = {
				x: 0,
				y: 0
			};
			this.startPos = {
				x: 0,
				y: 0
			}
		}(function() {
			var rect = [
				[0, 0, -1, -1],
				[0, 0, 0, -1],
				[0, 0, 1, -1],
				[0, 0, -1, 0],
				[0, 0, 1, 0],
				[0, 0, -1, 1],
				[0, 0, 0, 1],
				[0, 0, 1, 1]
			];
			Scale.prototype = {
				init: function(editor) {
					var me = this;
					me.editor = editor;
					me.startPos = this.prePos = {
						x: 0,
						y: 0
					};
					me.dragId = -1;
					var hands = [],
						cover = me.cover = document.createElement("div"),
						resizer = me.resizer = document.createElement("div");
					cover.id = me.editor.ui.id + "_imagescale_cover";
					cover.style.cssText = "position:absolute;display:none;z-index:" + me.editor
						.options.zIndex + ";filter:alpha(opacity=0); opacity:0;background:#CCC;";
					domUtils.on(cover, "mousedown", function(e) {
						me.hide()
					});
					for (var i = 0; i < 8; i++) {
						hands.push('<span class="edui-editor-imagescale-hand' + i + '"></span>')
					}
					resizer.id = me.editor.ui.id + "_imagescale";
					resizer.className = "edui-editor-imagescale";
					resizer.innerHTML = hands.join("");
					resizer.style.cssText += ";display:none;border:1px solid #3b77ff;z-index:" + me
						.editor.options.zIndex + ";";
					me.editor.ui.getDom().appendChild(cover);
					me.editor.ui.getDom().appendChild(resizer);
					me.initStyle();
					me.initEvents()
				},
				initStyle: function() {
					utils.cssRule("imagescale",
						".edui-editor-imagescale{display:none;position:absolute;border:1px solid #38B2CE;cursor:hand;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;}" +
						".edui-editor-imagescale span{position:absolute;width:6px;height:6px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}" +
						".edui-editor-imagescale .edui-editor-imagescale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}"
						)
				},
				initEvents: function() {
					var me = this;
					me.startPos.x = me.startPos.y = 0;
					me.isDraging = false
				},
				_eventHandler: function(e) {
					var me = this;
					switch (e.type) {
						case "mousedown":
							var hand = e.target || e.srcElement,
								hand;
							if (hand.className.indexOf("edui-editor-imagescale-hand") !== -1 && me
								.dragId === -1) {
								me.dragId = hand.className.slice(-1);
								me.startPos.x = me.prePos.x = e.clientX;
								me.startPos.y = me.prePos.y = e.clientY;
								domUtils.on(me.doc, "mousemove", me.proxy(me._eventHandler, me))
							}
							break;
						case "mousemove":
							if (me.dragId !== -1) {
								me.updateContainerStyle(me.dragId, {
									x: e.clientX - me.prePos.x,
									y: e.clientY - me.prePos.y
								});
								me.prePos.x = e.clientX;
								me.prePos.y = e.clientY;
								elementUpdated = true;
								me.updateTargetElement()
							}
							break;
						case "mouseup":
							if (me.dragId !== -1) {
								me.updateContainerStyle(me.dragId, {
									x: e.clientX - me.prePos.x,
									y: e.clientY - me.prePos.y
								});
								me.updateTargetElement();
								if (me.target.parentNode) {
									me.attachTo(me.target)
								}
								me.dragId = -1
							}
							domUtils.un(me.doc, "mousemove", me.proxy(me._eventHandler, me));
							if (elementUpdated) {
								elementUpdated = false;
								me.editor.fireEvent("contentchange")
							}
							break;
						default:
							break
					}
				},
				updateTargetElement: function() {
					var me = this;
					domUtils.setStyles(me.target, {
						width: me.resizer.style.width,
						height: me.resizer.style.height
					});
					me.target.width = parseInt(me.resizer.style.width);
					me.target.height = parseInt(me.resizer.style.height);
					me.attachTo(me.target)
				},
				updateContainerStyle: function(dir, offset) {
					var me = this,
						dom = me.resizer,
						tmp;
					if (rect[dir][0] != 0) {
						tmp = parseInt(dom.style.left) + offset.x;
						dom.style.left = me._validScaledProp("left", tmp) + "px"
					}
					if (rect[dir][1] != 0) {
						tmp = parseInt(dom.style.top) + offset.y;
						dom.style.top = me._validScaledProp("top", tmp) + "px"
					}
					if (rect[dir][2] != 0) {
						tmp = dom.clientWidth + rect[dir][2] * offset.x;
						dom.style.width = me._validScaledProp("width", tmp) + "px"
					}
					if (rect[dir][3] != 0) {
						tmp = dom.clientHeight + rect[dir][3] * offset.y;
						dom.style.height = me._validScaledProp("height", tmp) + "px"
					}
				},
				_validScaledProp: function(prop, value) {
					var ele = this.resizer,
						wrap = document;
					value = isNaN(value) ? 0 : value;
					switch (prop) {
						case "left":
							return value < 0 ? 0 : value + ele.clientWidth > wrap.clientWidth ? wrap
								.clientWidth - ele.clientWidth : value;
						case "top":
							return value < 0 ? 0 : value + ele.clientHeight > wrap.clientHeight ?
								wrap.clientHeight - ele.clientHeight : value;
						case "width":
							return value <= 0 ? 1 : value + ele.offsetLeft > wrap.clientWidth ? wrap
								.clientWidth - ele.offsetLeft : value;
						case "height":
							return value <= 0 ? 1 : value + ele.offsetTop > wrap.clientHeight ? wrap
								.clientHeight - ele.offsetTop : value
					}
				},
				hideCover: function() {
					this.cover.style.display = "none"
				},
				showCover: function() {
					var me = this,
						editorPos = domUtils.getXY(me.editor.ui.getDom()),
						iframePos = domUtils.getXY(me.editor.iframe);
					domUtils.setStyles(me.cover, {
						width: me.editor.iframe.offsetWidth + "px",
						height: me.editor.iframe.offsetHeight + "px",
						top: iframePos.y - editorPos.y + "px",
						left: iframePos.x - editorPos.x + "px",
						position: "absolute",
						display: ""
					})
				},
				show: function(targetObj) {
					var me = this;
					me.resizer.style.display = "block";
					if (targetObj) {
						me.attachTo(targetObj)
					}
					domUtils.on(this.resizer, "mousedown", me.proxy(me._eventHandler, me));
					domUtils.on(me.doc, "mouseup", me.proxy(me._eventHandler, me));
					me.showCover();
					me.editor.fireEvent("afterscaleshow", me);
					me.editor.fireEvent("saveScene")
				},
				hide: function() {
					var me = this;
					me.hideCover();
					me.resizer.style.display = "none";
					domUtils.un(me.resizer, "mousedown", me.proxy(me._eventHandler, me));
					domUtils.un(me.doc, "mouseup", me.proxy(me._eventHandler, me));
					me.editor.fireEvent("afterscalehide", me)
				},
				proxy: function(fn, context) {
					return function(e) {
						return fn.apply(context || this, arguments)
					}
				},
				attachTo: function(targetObj) {
					var me = this,
						target = me.target = targetObj,
						resizer = this.resizer,
						imgPos = domUtils.getXY(target),
						iframePos = domUtils.getXY(me.editor.iframe),
						editorPos = domUtils.getXY(resizer.parentNode);
					domUtils.setStyles(resizer, {
						width: target.width + "px",
						height: target.height + "px",
						left: iframePos.x + imgPos.x - me.editor.getScrollLeft() - editorPos
							.x - parseInt(resizer.style.borderLeftWidth) + "px",
						top: iframePos.y + imgPos.y - me.editor.getScrollTop() - editorPos
							.y - parseInt(resizer.style.borderTopWidth) + "px"
					})
				}
			}
		})();
		return function() {
			var me = this,
				imageScale;
			me.setOpt("imageScaleEnabled", true);
			if (!browser.ie && me.options.imageScaleEnabled) {
				me.addListener("click", function(type, e) {
					var range = me.selection.getRange(),
						img = range.getClosedNode();
					if (img && img.tagName === "IMG" && me.body.contentEditable !== "false" &&
						img === e.target) {
						if (img.getAttribute("anchorname") || domUtils.hasClass(img,
							"uep-loading") || domUtils.hasClass(img, "uep-loading-error")) {
							return
						}
						if (!imageScale) {
							imageScale = new Scale;
							imageScale.init(me);
							me.ui.getDom().appendChild(imageScale.resizer);
							var _keyDownHandler = function(e) {
									imageScale.hide();
									if (imageScale.target) {
										me.selection.getRange().selectNode(imageScale.target)
											.select()
									}
								},
								_mouseDownHandler = function(e) {
									var ele = e.target || e.srcElement;
									if (ele && (ele.className === undefined || ele.className
											.indexOf("edui-editor-imagescale") === -1)) {
										_keyDownHandler(e)
									}
								},
								timer;
							me.addListener("afterscaleshow", function(e) {
								me.addListener("beforekeydown", _keyDownHandler);
								me.addListener("beforemousedown", _mouseDownHandler);
								domUtils.on(document, "keydown", _keyDownHandler);
								domUtils.on(document, "mousedown", _mouseDownHandler);
								me.selection.getNative().removeAllRanges()
							});
							me.addListener("afterscalehide", function(e) {
								me.removeListener("beforekeydown", _keyDownHandler);
								me.removeListener("beforemousedown", _mouseDownHandler);
								domUtils.un(document, "keydown", _keyDownHandler);
								domUtils.un(document, "mousedown", _mouseDownHandler);
								var target = imageScale.target;
								if (target.parentNode) {
									me.selection.getRange().selectNode(target).select()
								}
							});
							domUtils.on(imageScale.resizer, "mousedown", function(e) {
								me.selection.getNative().removeAllRanges();
								var ele = e.target || e.srcElement;
								if (ele && ele.className.indexOf(
										"edui-editor-imagescale-hand") === -1) {
									timer = setTimeout(function() {
										imageScale.hide();
										if (imageScale.target) me.selection
											.getRange().selectNode(ele).select()
									}, 200)
								}
							});
							domUtils.on(imageScale.resizer, "mouseup", function(e) {
								var ele = e.target || e.srcElement;
								if (ele && ele.className.indexOf(
										"edui-editor-imagescale-hand") === -1) {
									clearTimeout(timer)
								}
							})
						}
						imageScale.show(img)
					} else {
						if (imageScale && imageScale.resizer.style.display !== "none") {
							imageScale.hide()
						}
					}
				})
			}
			if (browser.webkit) {
				me.addListener("click", function(type, e) {
					if (e.target.tagName === "IMG" && me.body.contentEditable !== "false") {
						var range = new dom.Range(me.document);
						range.selectNode(e.target).select()
					}
				})
			}
		}
	}();
	UE.plugin.register("autolink", function() {
		var cont = 0;
		return !browser.ie ? {
			bindEvents: {
				reset: function() {
					cont = 0
				},
				keydown: function(type, evt) {
					var me = this;
					var keyCode = evt.keyCode || evt.which;
					if (keyCode == 32 || keyCode == 13) {
						var sel = me.selection.getNative(),
							range = sel.getRangeAt(0).cloneRange(),
							offset, charCode;
						var start = range.startContainer;
						while (start.nodeType == 1 && range.startOffset > 0) {
							start = range.startContainer.childNodes[range.startOffset - 1];
							if (!start) {
								break
							}
							range.setStart(start, start.nodeType == 1 ? start.childNodes.length :
								start.nodeValue.length);
							range.collapse(true);
							start = range.startContainer
						}
						do {
							if (range.startOffset == 0) {
								start = range.startContainer.previousSibling;
								while (start && start.nodeType == 1) {
									start = start.lastChild
								}
								if (!start || domUtils.isFillChar(start)) {
									break
								}
								offset = start.nodeValue.length
							} else {
								start = range.startContainer;
								offset = range.startOffset
							}
							range.setStart(start, offset - 1);
							charCode = range.toString().charCodeAt(0)
						} while (charCode != 160 && charCode != 32);
						if (range.toString().replace(new RegExp(domUtils.fillChar, "g"), "").match(
								/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)) {
							while (range.toString().length) {
								if (/^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(range
										.toString())) {
									break
								}
								try {
									range.setStart(range.startContainer, range.startOffset + 1)
								} catch (e) {
									var start = range.startContainer;
									while (!(next = start.nextSibling)) {
										if (domUtils.isBody(start)) {
											return
										}
										start = start.parentNode
									}
									range.setStart(next, 0)
								}
							}
							if (domUtils.findParentByTagName(range.startContainer, "a", true)) {
								return
							}
							var a = me.document.createElement("a"),
								text = me.document.createTextNode(" "),
								href;
							me.undoManger && me.undoManger.save();
							a.appendChild(range.extractContents());
							a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, "");
							href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar,
								"g"), "");
							href = /^(?:https?:\/\/)/gi.test(href) ? href : "http://" + href;
							a.setAttribute("_src", utils.html(href));
							a.href = utils.html(href);
							range.insertNode(a);
							a.parentNode.insertBefore(text, a.nextSibling);
							range.setStart(text, 0);
							range.collapse(true);
							sel.removeAllRanges();
							sel.addRange(range);
							me.undoManger && me.undoManger.save()
						}
					}
				}
			}
		} : {}
	}, function() {
		var keyCodes = {
			37: 1,
			38: 1,
			39: 1,
			40: 1,
			13: 1,
			32: 1
		};

		function checkIsCludeLink(node) {
			if (node.nodeType == 3) {
				return null
			}
			if (node.nodeName == "A") {
				return node
			}
			var lastChild = node.lastChild;
			while (lastChild) {
				if (lastChild.nodeName == "A") {
					return lastChild
				}
				if (lastChild.nodeType == 3) {
					if (domUtils.isWhitespace(lastChild)) {
						lastChild = lastChild.previousSibling;
						continue
					}
					return null
				}
				lastChild = lastChild.lastChild
			}
		}
		browser.ie && this.addListener("keyup", function(cmd, evt) {
			var me = this,
				keyCode = evt.keyCode;
			if (keyCodes[keyCode]) {
				var rng = me.selection.getRange();
				var start = rng.startContainer;
				if (keyCode == 13) {
					while (start && !domUtils.isBody(start) && !domUtils.isBlockElm(start)) {
						start = start.parentNode
					}
					if (start && !domUtils.isBody(start) && start.nodeName == "P") {
						var pre = start.previousSibling;
						if (pre && pre.nodeType == 1) {
							var pre = checkIsCludeLink(pre);
							if (pre && !pre.getAttribute("_href")) {
								domUtils.remove(pre, true)
							}
						}
					}
				} else if (keyCode == 32) {
					if (start.nodeType == 3 && /^\s$/.test(start.nodeValue)) {
						start = start.previousSibling;
						if (start && start.nodeName == "A" && !start.getAttribute("_href")) {
							domUtils.remove(start, true)
						}
					}
				} else {
					start = domUtils.findParentByTagName(start, "a", true);
					if (start && !start.getAttribute("_href")) {
						var bk = rng.createBookmark();
						domUtils.remove(start, true);
						rng.moveToBookmark(bk).select(true)
					}
				}
			}
		})
	});
	UE.plugins["autoheight"] = function() {
		var me = this;
		me.autoHeightEnabled = me.options.autoHeightEnabled !== false;
		if (!me.autoHeightEnabled) {
			return
		}
		var bakOverflow, lastHeight = 0,
			options = me.options,
			currentHeight, timer;

		function adjustHeight() {
			var me = this;
			clearTimeout(timer);
			if (isFullscreen) return;
			if (!me.queryCommandState || me.queryCommandState && me.queryCommandState("source") != 1) {
				timer = setTimeout(function() {
					var node = me.body.lastChild;
					while (node && node.nodeType != 1) {
						node = node.previousSibling
					}
					if (node && node.nodeType == 1) {
						node.style.clear = "both";
						currentHeight = Math.max(domUtils.getXY(node).y + node.offsetHeight + 25, Math
							.max(options.minFrameHeight, options.initialFrameHeight));
						if (currentHeight !== lastHeight) {
							me.iframe.parentNode.style.transition =
								"width 0.3s, height 0.3s, easy-in-out";
							if (currentHeight !== parseInt(me.iframe.parentNode.style.height)) {
								me.iframe.parentNode.style.height = currentHeight + "px"
							}
							me.body.style.height = currentHeight + "px";
							lastHeight = currentHeight
						}
						domUtils.removeStyle(node, "clear")
					}
				}, 50)
			}
		}
		var isFullscreen;
		me.addListener("fullscreenchanged", function(cmd, f) {
			isFullscreen = f
		});
		me.addListener("destroy", function() {
			domUtils.un(me.window, "scroll", fixedScrollTop);
			me.removeListener("contentchange afterinserthtml keyup mouseup", adjustHeight)
		});
		me.enableAutoHeight = function() {
			var me = this;
			if (!me.autoHeightEnabled) {
				return
			}
			var doc = me.document;
			me.autoHeightEnabled = true;
			bakOverflow = doc.body.style.overflowY;
			doc.body.style.overflowY = "hidden";
			me.addListener("contentchange afterinserthtml keyup mouseup", adjustHeight);
			setTimeout(function() {
				adjustHeight.call(me)
			}, browser.gecko ? 100 : 0);
			me.fireEvent("autoheightchanged", me.autoHeightEnabled)
		};
		me.disableAutoHeight = function() {
			me.body.style.overflowY = bakOverflow || "";
			me.removeListener("contentchange", adjustHeight);
			me.removeListener("keyup", adjustHeight);
			me.removeListener("mouseup", adjustHeight);
			me.autoHeightEnabled = false;
			me.fireEvent("autoheightchanged", me.autoHeightEnabled)
		};
		me.on("setHeight", function() {
			me.disableAutoHeight()
		});
		me.addListener("ready", function() {
			me.enableAutoHeight();
			var timer;
			domUtils.on(browser.ie ? me.body : me.document, browser.webkit ? "dragover" : "drop",
				function() {
					clearTimeout(timer);
					timer = setTimeout(function() {
						adjustHeight.call(me)
					}, 100)
				});
			domUtils.on(me.window, "scroll", fixedScrollTop)
		});
		var lastScrollY;

		function fixedScrollTop() {
			if (!me.window) return;
			if (lastScrollY === null) {
				lastScrollY = me.window.scrollY
			} else if (me.window.scrollY == 0 && lastScrollY != 0) {
				me.window.scrollTo(0, 0);
				lastScrollY = null
			}
		}
	};
	UE.plugins["autofloat"] = function() {
		var me = this,
			lang = me.getLang();
		me.setOpt({
			topOffset: 0
		});
		var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
			topOffset = me.options.topOffset;
		if (!optsAutoFloatEnabled) {
			return
		}
		var uiUtils = UE.ui.uiUtils,
			LteIE6 = browser.ie && browser.version <= 6,
			quirks = browser.quirks;

		function checkHasUI() {
			if (!UE.ui) {
				alert(lang.autofloatMsg);
				return 0
			}
			return 1
		}

		function fixIE6FixedPos() {
			var docStyle = document.body.style;
			docStyle.backgroundImage = 'url("about:blank")';
			docStyle.backgroundAttachment = "fixed"
		}
		var bakCssText, placeHolder = document.createElement("div"),
			toolbarBox, orgTop, getPosition, flag = true;

		function setFloating() {
			var toobarBoxPos = domUtils.getXY(toolbarBox),
				origalFloat = domUtils.getComputedStyle(toolbarBox, "position"),
				origalLeft = domUtils.getComputedStyle(toolbarBox, "left");
			toolbarBox.style.width = toolbarBox.offsetWidth + "px";
			toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
			toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
			if (LteIE6 || quirks && browser.ie) {
				if (toolbarBox.style.position != "absolute") {
					toolbarBox.style.position = "absolute"
				}
				toolbarBox.style.top = (document.body.scrollTop || document.documentElement.scrollTop) -
					orgTop + topOffset + "px"
			} else {
				if (browser.ie7Compat && flag) {
					flag = false;
					toolbarBox.style.left = domUtils.getXY(toolbarBox).x - document.documentElement
						.getBoundingClientRect().left + 2 + "px"
				}
				if (toolbarBox.style.position != "fixed") {
					toolbarBox.style.position = "fixed";
					toolbarBox.style.top = topOffset + "px";
					(origalFloat == "absolute" || origalFloat == "relative") && parseFloat(origalLeft) && (
						toolbarBox.style.left = toobarBoxPos.x + "px")
				}
			}
		}

		function unsetFloating() {
			flag = true;
			if (placeHolder.parentNode) {
				placeHolder.parentNode.removeChild(placeHolder)
			}
			toolbarBox.style.cssText = bakCssText
		}
		me.unsetFloating = unsetFloating;

		function updateFloating() {
			var rect3 = getPosition(me.container);
			var offset = me.options.toolbarTopOffset || 0;
			if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
				setFloating()
			} else {
				unsetFloating()
			}
		}
		var defer_updateFloating = utils.defer(function() {
			updateFloating()
		}, browser.ie ? 200 : 100, true);
		me.addListener("destroy", function() {
			domUtils.un(window, ["scroll", "resize"], updateFloating);
			me.removeListener("keydown", defer_updateFloating)
		});
		me.addListener("ready", function() {
			if (checkHasUI(me)) {
				if (!me.ui) {
					return
				}
				getPosition = uiUtils.getClientRect;
				toolbarBox = me.ui.getDom("toolbarbox");
				orgTop = getPosition(toolbarBox).top;
				bakCssText = toolbarBox.style.cssText;
				placeHolder.style.height = toolbarBox.offsetHeight + "px";
				if (LteIE6) {
					fixIE6FixedPos()
				}
				domUtils.on(window, ["scroll", "resize"], updateFloating);
				me.addListener("keydown", defer_updateFloating);
				me.addListener("beforefullscreenchange", function(t, enabled) {
					if (enabled) {
						unsetFloating()
					}
				});
				me.addListener("fullscreenchanged", function(t, enabled) {
					if (!enabled) {
						updateFloating()
					}
				});
				me.addListener("sourcemodechanged", function(t, enabled) {
					setTimeout(function() {
						updateFloating()
					}, 0)
				});
				me.addListener("clearDoc", function() {
					setTimeout(function() {
						updateFloating()
					}, 0)
				})
			}
		})
	};
	UE.plugins["video"] = function() {
		var me = this;

        function creatInsertStr(url, width, height, id, align, classname, type, poster) {
			var str;
			switch (type) {
				case "iframe":
                    str = '<iframe class="' + classname + '" ' + ' src="' + utils.html(url) + '" width="' +
                        width + '" height="' + height + '"' + (poster ? ' data-poster="' + utils.html(poster) + '"' : '') + " frameborder=0 allowfullscreen>";
					break;
				case "image":
					str = "<img " + (id ? 'id="' + id + '"' : "") + ' width="' + width + '" height="' + height +
						'" _url="' + url + '" class="' + '"' + ' src="' + me.options.UEDITOR_HOME_URL +
						'themes/default/images/spacer.gif" style="background:url(' + me.options
						.UEDITOR_HOME_URL +
						"themes/default/images/videologo.gif) no-repeat center center; border:1px solid gray;" +
						(align ? "float:" + align + ";" : "") + '" />';
					break;
				case "embed":
                    str = '<embed type="application/x-shockwave-flash" class="' + classname +
						'" pluginspage="http://www.macromedia.com/go/getflashplayer"' + ' src="' + utils.html(
                            url) + '" width="' + width + '" height="' + height + '"' + (poster ? ' data-poster="' + utils.html(poster) + '"' : '') + (align ?
							' style="float:' + align + '"' : "") +
						' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
					break;
				case "video":
					var ext = url.substr(url.lastIndexOf(".") + 1);
					if (ext == "ogv") ext = "ogg";
                    str = "<video" + (id ? ' id="' + id + '"' : "") + ' class="' + classname + '" ' + (align ?
                            ' style="float:' + align + '"' : "") + (poster ? ' poster="' + utils.html(poster) + '"' : '') + ' controls preload="none" width="' + width +
                        '" height="' + height + '" src="' + url + '" data-setup="{}">' + '<source src="' + url +
						'" type="video/' + ext + '" /></video>';
					break
			}
			return str
		}

		function switchImgAndVideo(root, img2video) {
			utils.each(root.getNodesByTagName(img2video ? "img" : "embed video"), function(node) {
				var className = node.getAttr("class");
                if (className && className.indexOf("edui-faked-video") != -1) {
					var html = creatInsertStr(img2video ? node.getAttr("_url") : node.getAttr("src"),
						node.getAttr("width"), node.getAttr("height"), null, node.getStyle(
                        "float") || "", className, img2video ? "embed" : "image", null);
					node.parentNode.replaceChild(UE.uNode.createElement(html), node)
				}
				if (className && className.indexOf("edui-upload-video") != -1) {
					var html = creatInsertStr(img2video ? node.getAttr("_url") : node.getAttr("src"),
						node.getAttr("width"), node.getAttr("height"), null, node.getStyle(
                        "float") || "", className, img2video ? "video" : "image", null);
					node.parentNode.replaceChild(UE.uNode.createElement(html), node)
				}
			})
		}
		me.addOutputRule(function(root) {
			switchImgAndVideo(root, true)
		});
		me.addInputRule(function(root) {
			switchImgAndVideo(root)
		});
		me.commands["insertvideo"] = {
			execCommand: function(cmd, videoObjs, type) {
				videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs];
				if (me.fireEvent("beforeinsertvideo", videoObjs) === true) {
					return
				}
				var html = [],
					id = "tmpVideo",
					cl;
                for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
					vi = videoObjs[i];
					var videoType = "iframe";
					if (vi.url.match(/.mp4$/)) {
						videoType = "video"
					}
					cl = videoType == "iframe" ? "edui-video-iframe" : "edui-video-video";
                    html.push(creatInsertStr(vi.url, vi.width || 420, vi.height || 280, id + i, null,
                        cl, videoType, vi.poster || null))
				}
				me.execCommand("inserthtml", html.join(""), true);
				var rng = this.selection.getRange();
				me.fireEvent("afterinsertvideo", videoObjs)
			},
			queryCommandState: function() {
				var img = me.selection.getRange().getClosedNode(),
					flag = img && (img.className == "edui-video-iframe" || img.className.indexOf(
							"edui-video-iframe") != -1 || img.className == "edui-video-video" || img
						.className.indexOf("edui-video-video") != -1);
				return flag ? 1 : 0
			}
		}
	};
	UE.plugins["audio"] = function() {
		var me = this;

		function createAudioHtml(url, param) {
			param = param || {};
			var str = ["<audio", param.id ? ' id="' + param.id + '"' : "", param.cls ? ' class="' + param.cls +
				'"' : "", " controls >", '<source src="' + url + '" type="audio/mpeg' + '" />', "</audio>"
			];
			return str.join("")
		}

		function switchImgAndAudio(root, img2audio) {}
		me.addOutputRule(function(root) {
			switchImgAndAudio(root, true)
		});
		me.addInputRule(function(root) {
			switchImgAndAudio(root)
		});
		me.commands["insertaudio"] = {
			execCommand: function(cmd, audioObjs, type) {
				audioObjs = utils.isArray(audioObjs) ? audioObjs : [audioObjs];
				if (me.fireEvent("beforeinsertaudio", audioObjs) === true) {
					return
				}
				var html = [];
				for (var i = 0, vi, len = audioObjs.length; i < len; i++) {
					vi = audioObjs[i];
					html.push(createAudioHtml(vi.url, {
						cls: "edui-audio-audio"
					}))
				}
				me.execCommand("inserthtml", html.join(""), true);
				var rng = this.selection.getRange();
				me.fireEvent("afterinsertaudio", audioObjs)
			},
			queryCommandState: function() {
				var img = me.selection.getRange().getClosedNode(),
					flag = img && (img.className == "edui-audio-audio" || img.className.indexOf(
						"edui-audio-audio") != -1);
				return flag ? 1 : 0
			}
		}
	};
	(function() {
		var UETable = UE.UETable = function(table) {
			this.table = table;
			this.indexTable = [];
			this.selectedTds = [];
			this.cellsRange = {};
			this.update(table)
		};
		UETable.removeSelectedClass = function(cells) {
			utils.each(cells, function(cell) {
				domUtils.removeClasses(cell, "selectTdClass")
			})
		};
		UETable.addSelectedClass = function(cells) {
			utils.each(cells, function(cell) {
				domUtils.addClass(cell, "selectTdClass")
			})
		};
		UETable.isEmptyBlock = function(node) {
			var reg = new RegExp(domUtils.fillChar, "g");
			if (node[browser.ie ? "innerText" : "textContent"].replace(/^\s*$/, "").replace(reg, "")
				.length > 0) {
				return 0
			}
			for (var i in dtd.$isNotEmpty)
				if (dtd.$isNotEmpty.hasOwnProperty(i)) {
					if (node.getElementsByTagName(i).length) {
						return 0
					}
				} return 1
		};
		UETable.getWidth = function(cell) {
			if (!cell) return 0;
			return parseInt(domUtils.getComputedStyle(cell, "width"), 10)
		};
		UETable.getTableCellAlignState = function(cells) {
			!utils.isArray(cells) && (cells = [cells]);
			var result = {},
				status = ["align", "valign"],
				tempStatus = null,
				isSame = true;
			utils.each(cells, function(cellNode) {
				utils.each(status, function(currentState) {
					tempStatus = cellNode.getAttribute(currentState);
					if (!result[currentState] && tempStatus) {
						result[currentState] = tempStatus
					} else if (!result[currentState] || tempStatus !== result[
						currentState]) {
						isSame = false;
						return false
					}
				});
				return isSame
			});
			return isSame ? result : null
		};
		UETable.getTableItemsByRange = function(editor) {
			var start = editor.selection.getStart();
			if (start && start.id && start.id.indexOf("_baidu_bookmark_start_") === 0 && start
				.nextSibling) {
				start = start.nextSibling
			}
			var cell = start && domUtils.findParentByTagName(start, ["td", "th"], true),
				tr = cell && cell.parentNode,
				table = tr && domUtils.findParentByTagName(tr, ["table"]),
				caption = table && table.getElementsByTagName("caption")[0];
			return {
				cell: cell,
				tr: tr,
				table: table,
				caption: caption
			}
		};
		UETable.getUETableBySelected = function(editor) {
			var table = UETable.getTableItemsByRange(editor).table;
			if (table && table.ueTable && table.ueTable.selectedTds.length) {
				return table.ueTable
			}
			return null
		};
		UETable.getDefaultValue = function(editor, table) {
			var borderMap = {
					thin: "0px",
					medium: "1px",
					thick: "2px"
				},
				tableBorder, tdPadding, tdBorder, tmpValue;
			if (!table) {
				table = editor.document.createElement("table");
				table.insertRow(0).insertCell(0).innerHTML = "xxx";
				editor.body.appendChild(table);
				var td = table.getElementsByTagName("td")[0];
				tmpValue = domUtils.getComputedStyle(table, "border-left-width");
				tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
				tmpValue = domUtils.getComputedStyle(td, "padding-left");
				tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
				tmpValue = domUtils.getComputedStyle(td, "border-left-width");
				tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
				domUtils.remove(table);
				return {
					tableBorder: tableBorder,
					tdPadding: tdPadding,
					tdBorder: tdBorder
				}
			} else {
				td = table.getElementsByTagName("td")[0];
				tmpValue = domUtils.getComputedStyle(table, "border-left-width");
				tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
				tmpValue = domUtils.getComputedStyle(td, "padding-left");
				tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
				tmpValue = domUtils.getComputedStyle(td, "border-left-width");
				tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
				return {
					tableBorder: tableBorder,
					tdPadding: tdPadding,
					tdBorder: tdBorder
				}
			}
		};
		UETable.getUETable = function(tdOrTable) {
			var tag = tdOrTable.tagName.toLowerCase();
			tdOrTable = tag == "td" || tag == "th" || tag == "caption" ? domUtils.findParentByTagName(
				tdOrTable, "table", true) : tdOrTable;
			if (!tdOrTable.ueTable) {
				tdOrTable.ueTable = new UETable(tdOrTable)
			}
			return tdOrTable.ueTable
		};
		UETable.cloneCell = function(cell, ignoreMerge, keepPro) {
			if (!cell || utils.isString(cell)) {
				return this.table.ownerDocument.createElement(cell || "td")
			}
			var flag = domUtils.hasClass(cell, "selectTdClass");
			flag && domUtils.removeClasses(cell, "selectTdClass");
			var tmpCell = cell.cloneNode(true);
			if (ignoreMerge) {
				tmpCell.rowSpan = tmpCell.colSpan = 1
			}!keepPro && domUtils.removeAttributes(tmpCell, "width height");
			!keepPro && domUtils.removeAttributes(tmpCell, "style");
			tmpCell.style.borderLeftStyle = "";
			tmpCell.style.borderTopStyle = "";
			tmpCell.style.borderLeftColor = cell.style.borderRightColor;
			tmpCell.style.borderLeftWidth = cell.style.borderRightWidth;
			tmpCell.style.borderTopColor = cell.style.borderBottomColor;
			tmpCell.style.borderTopWidth = cell.style.borderBottomWidth;
			flag && domUtils.addClass(cell, "selectTdClass");
			return tmpCell
		};
		UETable.prototype = {
			getMaxRows: function() {
				var rows = this.table.rows,
					maxLen = 1;
				for (var i = 0, row; row = rows[i]; i++) {
					var currentMax = 1;
					for (var j = 0, cj; cj = row.cells[j++];) {
						currentMax = Math.max(cj.rowSpan || 1, currentMax)
					}
					maxLen = Math.max(currentMax + i, maxLen)
				}
				return maxLen
			},
			getMaxCols: function() {
				var rows = this.table.rows,
					maxLen = 0,
					cellRows = {};
				for (var i = 0, row; row = rows[i]; i++) {
					var cellsNum = 0;
					for (var j = 0, cj; cj = row.cells[j++];) {
						cellsNum += cj.colSpan || 1;
						if (cj.rowSpan && cj.rowSpan > 1) {
							for (var k = 1; k < cj.rowSpan; k++) {
								if (!cellRows["row_" + (i + k)]) {
									cellRows["row_" + (i + k)] = cj.colSpan || 1
								} else {
									cellRows["row_" + (i + k)]++
								}
							}
						}
					}
					cellsNum += cellRows["row_" + i] || 0;
					maxLen = Math.max(cellsNum, maxLen)
				}
				return maxLen
			},
			getCellColIndex: function(cell) {},
			getHSideCell: function(cell, right) {
				try {
					var cellInfo = this.getCellInfo(cell),
						previewRowIndex, previewColIndex;
					var len = this.selectedTds.length,
						range = this.cellsRange;
					if (!right && (!len ? !cellInfo.colIndex : !range.beginColIndex) || right && (!len ?
							cellInfo.colIndex == this.colsNum - 1 : range.endColIndex == this.colsNum -
							1)) return null;
					previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex;
					previewColIndex = !right ? !len ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex -
						1 : range.beginColIndex - 1 : !len ? cellInfo.colIndex + 1 : range.endColIndex +
						1;
					return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this
						.indexTable[previewRowIndex][previewColIndex].cellIndex)
				} catch (e) {
					showError(e)
				}
			},
			getTabNextCell: function(cell, preRowIndex) {
				var cellInfo = this.getCellInfo(cell),
					rowIndex = preRowIndex || cellInfo.rowIndex,
					colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
					nextCell;
				try {
					nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this
						.indexTable[rowIndex][colIndex].cellIndex)
				} catch (e) {
					try {
						rowIndex = rowIndex * 1 + 1;
						colIndex = 0;
						nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this
							.indexTable[rowIndex][colIndex].cellIndex)
					} catch (e) {}
				}
				return nextCell
			},
			getVSideCell: function(cell, bottom, ignoreRange) {
				try {
					var cellInfo = this.getCellInfo(cell),
						nextRowIndex, nextColIndex;
					var len = this.selectedTds.length && !ignoreRange,
						range = this.cellsRange;
					if (!bottom && cellInfo.rowIndex == 0 || bottom && (!len ? cellInfo.rowIndex +
							cellInfo.rowSpan > this.rowsNum - 1 : range.endRowIndex == this.rowsNum - 1
							)) return null;
					nextRowIndex = !bottom ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1 : !
						len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
					nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
					return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this
						.indexTable[nextRowIndex][nextColIndex].cellIndex)
				} catch (e) {
					showError(e)
				}
			},
			getSameEndPosCells: function(cell, xOrY) {
				try {
					var flag = xOrY.toLowerCase() === "x",
						end = domUtils.getXY(cell)[flag ? "x" : "y"] + cell["offset" + (flag ? "Width" :
							"Height")],
						rows = this.table.rows,
						cells = null,
						returns = [];
					for (var i = 0; i < this.rowsNum; i++) {
						cells = rows[i].cells;
						for (var j = 0, tmpCell; tmpCell = cells[j++];) {
							var tmpEnd = domUtils.getXY(tmpCell)[flag ? "x" : "y"] + tmpCell["offset" +
								(flag ? "Width" : "Height")];
							if (tmpEnd > end && flag) break;
							if (cell == tmpCell || end == tmpEnd) {
								if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) {
									returns.push(tmpCell)
								}
								if (flag) break
							}
						}
					}
					return returns
				} catch (e) {
					showError(e)
				}
			},
			setCellContent: function(cell, content) {
				cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "<br />")
			},
			cloneCell: UETable.cloneCell,
			getSameStartPosXCells: function(cell) {
				try {
					var start = domUtils.getXY(cell).x + cell.offsetWidth,
						rows = this.table.rows,
						cells, returns = [];
					for (var i = 0; i < this.rowsNum; i++) {
						cells = rows[i].cells;
						for (var j = 0, tmpCell; tmpCell = cells[j++];) {
							var tmpStart = domUtils.getXY(tmpCell).x;
							if (tmpStart > start) break;
							if (tmpStart == start && tmpCell.colSpan == 1) {
								returns.push(tmpCell);
								break
							}
						}
					}
					return returns
				} catch (e) {
					showError(e)
				}
			},
			update: function(table) {
				this.table = table || this.table;
				this.selectedTds = [];
				this.cellsRange = {};
				this.indexTable = [];
				var rows = this.table.rows,
					rowsNum = this.getMaxRows(),
					dNum = rowsNum - rows.length,
					colsNum = this.getMaxCols();
				while (dNum--) {
					this.table.insertRow(rows.length)
				}
				this.rowsNum = rowsNum;
				this.colsNum = colsNum;
				for (var i = 0, len = rows.length; i < len; i++) {
					this.indexTable[i] = new Array(colsNum)
				}
				for (var rowIndex = 0, row; row = rows[rowIndex]; rowIndex++) {
					for (var cellIndex = 0, cell, cells = row.cells; cell = cells[
						cellIndex]; cellIndex++) {
						if (cell.rowSpan > rowsNum) {
							cell.rowSpan = rowsNum
						}
						var colIndex = cellIndex,
							rowSpan = cell.rowSpan || 1,
							colSpan = cell.colSpan || 1;
						while (this.indexTable[rowIndex][colIndex]) colIndex++;
						for (var j = 0; j < rowSpan; j++) {
							for (var k = 0; k < colSpan; k++) {
								this.indexTable[rowIndex + j][colIndex + k] = {
									rowIndex: rowIndex,
									cellIndex: cellIndex,
									colIndex: colIndex,
									rowSpan: rowSpan,
									colSpan: colSpan
								}
							}
						}
					}
				}
				for (j = 0; j < rowsNum; j++) {
					for (k = 0; k < colsNum; k++) {
						if (this.indexTable[j][k] === undefined) {
							row = rows[j];
							cell = row.cells[row.cells.length - 1];
							cell = cell ? cell.cloneNode(true) : this.table.ownerDocument.createElement(
								"td");
							this.setCellContent(cell);
							if (cell.colSpan !== 1) cell.colSpan = 1;
							if (cell.rowSpan !== 1) cell.rowSpan = 1;
							row.appendChild(cell);
							this.indexTable[j][k] = {
								rowIndex: j,
								cellIndex: cell.cellIndex,
								colIndex: k,
								rowSpan: 1,
								colSpan: 1
							}
						}
					}
				}
				var tds = domUtils.getElementsByTagName(this.table, "td"),
					selectTds = [];
				utils.each(tds, function(td) {
					if (domUtils.hasClass(td, "selectTdClass")) {
						selectTds.push(td)
					}
				});
				if (selectTds.length) {
					var start = selectTds[0],
						end = selectTds[selectTds.length - 1],
						startInfo = this.getCellInfo(start),
						endInfo = this.getCellInfo(end);
					this.selectedTds = selectTds;
					this.cellsRange = {
						beginRowIndex: startInfo.rowIndex,
						beginColIndex: startInfo.colIndex,
						endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
						endColIndex: endInfo.colIndex + endInfo.colSpan - 1
					}
				}
				if (!domUtils.hasClass(this.table.rows[0], "firstRow")) {
					domUtils.addClass(this.table.rows[0], "firstRow");
					for (var i = 1; i < this.table.rows.length; i++) {
						domUtils.removeClasses(this.table.rows[i], "firstRow")
					}
				}
			},
			getCellInfo: function(cell) {
				if (!cell) return;
				var cellIndex = cell.cellIndex,
					rowIndex = cell.parentNode.rowIndex,
					rowInfo = this.indexTable[rowIndex],
					numCols = this.colsNum;
				for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
					var cellInfo = rowInfo[colIndex];
					if (cellInfo.rowIndex === rowIndex && cellInfo.cellIndex === cellIndex) {
						return cellInfo
					}
				}
			},
			getCell: function(rowIndex, cellIndex) {
				return rowIndex < this.rowsNum && this.table.rows[rowIndex].cells[cellIndex] || null
			},
			deleteCell: function(cell, rowIndex) {
				rowIndex = typeof rowIndex == "number" ? rowIndex : cell.parentNode.rowIndex;
				var row = this.table.rows[rowIndex];
				row.deleteCell(cell.cellIndex)
			},
			getCellsRange: function(cellA, cellB) {
				function checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex) {
					var tmpBeginRowIndex = beginRowIndex,
						tmpBeginColIndex = beginColIndex,
						tmpEndRowIndex = endRowIndex,
						tmpEndColIndex = endColIndex,
						cellInfo, colIndex, rowIndex;
					if (beginRowIndex > 0) {
						for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
							cellInfo = me.indexTable[beginRowIndex][colIndex];
							rowIndex = cellInfo.rowIndex;
							if (rowIndex < beginRowIndex) {
								tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex)
							}
						}
					}
					if (endColIndex < me.colsNum) {
						for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
							cellInfo = me.indexTable[rowIndex][endColIndex];
							colIndex = cellInfo.colIndex + cellInfo.colSpan - 1;
							if (colIndex > endColIndex) {
								tmpEndColIndex = Math.max(colIndex, tmpEndColIndex)
							}
						}
					}
					if (endRowIndex < me.rowsNum) {
						for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
							cellInfo = me.indexTable[endRowIndex][colIndex];
							rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1;
							if (rowIndex > endRowIndex) {
								tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex)
							}
						}
					}
					if (beginColIndex > 0) {
						for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
							cellInfo = me.indexTable[rowIndex][beginColIndex];
							colIndex = cellInfo.colIndex;
							if (colIndex < beginColIndex) {
								tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex)
							}
						}
					}
					if (tmpBeginRowIndex != beginRowIndex || tmpBeginColIndex != beginColIndex ||
						tmpEndRowIndex != endRowIndex || tmpEndColIndex != endColIndex) {
						return checkRange(tmpBeginRowIndex, tmpBeginColIndex, tmpEndRowIndex,
							tmpEndColIndex)
					} else {
						return {
							beginRowIndex: beginRowIndex,
							beginColIndex: beginColIndex,
							endRowIndex: endRowIndex,
							endColIndex: endColIndex
						}
					}
				}
				try {
					var me = this,
						cellAInfo = me.getCellInfo(cellA);
					if (cellA === cellB) {
						return {
							beginRowIndex: cellAInfo.rowIndex,
							beginColIndex: cellAInfo.colIndex,
							endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
							endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1
						}
					}
					var cellBInfo = me.getCellInfo(cellB);
					var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
						beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
						endRowIndex = Math.max(cellAInfo.rowIndex + cellAInfo.rowSpan - 1, cellBInfo
							.rowIndex + cellBInfo.rowSpan - 1),
						endColIndex = Math.max(cellAInfo.colIndex + cellAInfo.colSpan - 1, cellBInfo
							.colIndex + cellBInfo.colSpan - 1);
					return checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex)
				} catch (e) {}
			},
			getCells: function(range) {
				this.clearSelected();
				var beginRowIndex = range.beginRowIndex,
					beginColIndex = range.beginColIndex,
					endRowIndex = range.endRowIndex,
					endColIndex = range.endColIndex,
					cellInfo, rowIndex, colIndex, tdHash = {},
					returnTds = [];
				for (var i = beginRowIndex; i <= endRowIndex; i++) {
					for (var j = beginColIndex; j <= endColIndex; j++) {
						cellInfo = this.indexTable[i][j];
						rowIndex = cellInfo.rowIndex;
						colIndex = cellInfo.colIndex;
						var key = rowIndex + "|" + colIndex;
						if (tdHash[key]) continue;
						tdHash[key] = 1;
						if (rowIndex < i || colIndex < j || rowIndex + cellInfo.rowSpan - 1 >
							endRowIndex || colIndex + cellInfo.colSpan - 1 > endColIndex) {
							return null
						}
						returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex))
					}
				}
				return returnTds
			},
			clearSelected: function() {
				UETable.removeSelectedClass(this.selectedTds);
				this.selectedTds = [];
				this.cellsRange = {}
			},
			setSelected: function(range) {
				var cells = this.getCells(range);
				UETable.addSelectedClass(cells);
				this.selectedTds = cells;
				this.cellsRange = range
			},
			isFullRow: function() {
				var range = this.cellsRange;
				return range.endColIndex - range.beginColIndex + 1 == this.colsNum
			},
			isFullCol: function() {
				var range = this.cellsRange,
					table = this.table,
					ths = table.getElementsByTagName("th"),
					rows = range.endRowIndex - range.beginRowIndex + 1;
				return !ths.length ? rows == this.rowsNum : rows == this.rowsNum || rows == this
					.rowsNum - 1
			},
			getNextCell: function(cell, bottom, ignoreRange) {
				try {
					var cellInfo = this.getCellInfo(cell),
						nextRowIndex, nextColIndex;
					var len = this.selectedTds.length && !ignoreRange,
						range = this.cellsRange;
					if (!bottom && cellInfo.rowIndex == 0 || bottom && (!len ? cellInfo.rowIndex +
							cellInfo.rowSpan > this.rowsNum - 1 : range.endRowIndex == this.rowsNum - 1
							)) return null;
					nextRowIndex = !bottom ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1 : !
						len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
					nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
					return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this
						.indexTable[nextRowIndex][nextColIndex].cellIndex)
				} catch (e) {
					showError(e)
				}
			},
			getPreviewCell: function(cell, top) {
				try {
					var cellInfo = this.getCellInfo(cell),
						previewRowIndex, previewColIndex;
					var len = this.selectedTds.length,
						range = this.cellsRange;
					if (!top && (!len ? !cellInfo.colIndex : !range.beginColIndex) || top && (!len ?
							cellInfo.rowIndex > this.colsNum - 1 : range.endColIndex == this.colsNum - 1
							)) return null;
					previewRowIndex = !top ? !len ? cellInfo.rowIndex : range.beginRowIndex : !len ?
						cellInfo.rowIndex < 1 ? 0 : cellInfo.rowIndex - 1 : range.beginRowIndex;
					previewColIndex = !top ? !len ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1 :
						range.beginColIndex - 1 : !len ? cellInfo.colIndex : range.endColIndex + 1;
					return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this
						.indexTable[previewRowIndex][previewColIndex].cellIndex)
				} catch (e) {
					showError(e)
				}
			},
			moveContent: function(cellTo, cellFrom) {
				if (UETable.isEmptyBlock(cellFrom)) return;
				if (UETable.isEmptyBlock(cellTo)) {
					cellTo.innerHTML = cellFrom.innerHTML;
					return
				}
				var child = cellTo.lastChild;
				if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
					cellTo.appendChild(cellTo.ownerDocument.createElement("br"))
				}
				while (child = cellFrom.firstChild) {
					cellTo.appendChild(child)
				}
			},
			mergeRight: function(cell) {
				var cellInfo = this.getCellInfo(cell),
					rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
					rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
					rightCell = this.getCell(rightCellInfo.rowIndex, rightCellInfo.cellIndex);
				cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan;
				cell.removeAttribute("width");
				this.moveContent(cell, rightCell);
				this.deleteCell(rightCell, rightCellInfo.rowIndex);
				this.update()
			},
			mergeDown: function(cell) {
				var cellInfo = this.getCellInfo(cell),
					downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
					downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
					downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex);
				cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan;
				cell.removeAttribute("height");
				this.moveContent(cell, downCell);
				this.deleteCell(downCell, downCellInfo.rowIndex);
				this.update()
			},
			mergeRange: function() {
				var range = this.cellsRange,
					leftTopCell = this.getCell(range.beginRowIndex, this.indexTable[range.beginRowIndex]
						[range.beginColIndex].cellIndex);
				var cells = this.getCells(range);
				for (var i = 0, ci; ci = cells[i++];) {
					if (ci !== leftTopCell) {
						this.moveContent(leftTopCell, ci);
						this.deleteCell(ci)
					}
				}
				leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
				leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
				leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
				leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
				if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
					leftTopCell.colSpan = 1
				}
				if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
					var rowIndex = leftTopCell.parentNode.rowIndex;
					if (this.table.deleteRow) {
						for (var i = rowIndex + 1, curIndex = rowIndex + 1, len = leftTopCell
							.rowSpan; i < len; i++) {
							this.table.deleteRow(curIndex)
						}
					} else {
						for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
							var row = this.table.rows[rowIndex + 1];
							row.parentNode.removeChild(row)
						}
					}
					leftTopCell.rowSpan = 1
				}
				this.update()
			},
			insertRow: function(rowIndex, sourceCell) {
				var numCols = this.colsNum,
					table = this.table,
					row = table.insertRow(rowIndex),
					cell, thead = null,
					isInsertTitle = typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";

				function replaceTdToTh(colIndex, cell, tableRow) {
					if (colIndex == 0) {
						var tr = tableRow.nextSibling || tableRow.previousSibling,
							th = tr.cells[colIndex];
						if (th.tagName == "TH") {
							th = cell.ownerDocument.createElement("th");
							th.appendChild(cell.firstChild);
							tableRow.insertBefore(th, cell);
							domUtils.remove(cell)
						}
					} else {
						if (cell.tagName == "TH") {
							var td = cell.ownerDocument.createElement("td");
							td.appendChild(cell.firstChild);
							tableRow.insertBefore(td, cell);
							domUtils.remove(cell)
						}
					}
				}
				if (rowIndex == 0 || rowIndex == this.rowsNum) {
					for (var colIndex = 0; colIndex < numCols; colIndex++) {
						cell = this.cloneCell(sourceCell, true);
						this.setCellContent(cell);
						cell.getAttribute("vAlign") && cell.setAttribute("vAlign", cell.getAttribute(
							"vAlign"));
						row.appendChild(cell);
						if (!isInsertTitle) replaceTdToTh(colIndex, cell, row)
					}
					if (isInsertTitle) {
						thead = table.createTHead();
						thead.insertBefore(row, thead.firstChild)
					}
				} else {
					var infoRow = this.indexTable[rowIndex],
						cellIndex = 0;
					for (colIndex = 0; colIndex < numCols; colIndex++) {
						var cellInfo = infoRow[colIndex];
						if (cellInfo.rowIndex < rowIndex) {
							cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
							cell.rowSpan = cellInfo.rowSpan + 1
						} else {
							cell = this.cloneCell(sourceCell, true);
							this.setCellContent(cell);
							row.appendChild(cell)
						}
						if (!isInsertTitle) replaceTdToTh(colIndex, cell, row)
					}
				}
				this.update();
				return row
			},
			deleteRow: function(rowIndex) {
				var row = this.table.rows[rowIndex],
					infoRow = this.indexTable[rowIndex],
					colsNum = this.colsNum,
					count = 0;
				for (var colIndex = 0; colIndex < colsNum;) {
					var cellInfo = infoRow[colIndex],
						cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
					if (cell.rowSpan > 1) {
						if (cellInfo.rowIndex == rowIndex) {
							var clone = cell.cloneNode(true);
							clone.rowSpan = cell.rowSpan - 1;
							clone.innerHTML = "";
							cell.rowSpan = 1;
							var nextRowIndex = rowIndex + 1,
								nextRow = this.table.rows[nextRowIndex],
								insertCellIndex, preMerged = this.getPreviewMergedCellsNum(nextRowIndex,
									colIndex) - count;
							if (preMerged < colIndex) {
								insertCellIndex = colIndex - preMerged - 1;
								domUtils.insertAfter(nextRow.cells[insertCellIndex], clone)
							} else {
								if (nextRow.cells.length) nextRow.insertBefore(clone, nextRow.cells[0])
							}
							count += 1
						}
					}
					colIndex += cell.colSpan || 1
				}
				var deleteTds = [],
					cacheMap = {};
				for (colIndex = 0; colIndex < colsNum; colIndex++) {
					var tmpRowIndex = infoRow[colIndex].rowIndex,
						tmpCellIndex = infoRow[colIndex].cellIndex,
						key = tmpRowIndex + "_" + tmpCellIndex;
					if (cacheMap[key]) continue;
					cacheMap[key] = 1;
					cell = this.getCell(tmpRowIndex, tmpCellIndex);
					deleteTds.push(cell)
				}
				var mergeTds = [];
				utils.each(deleteTds, function(td) {
					if (td.rowSpan == 1) {
						td.parentNode.removeChild(td)
					} else {
						mergeTds.push(td)
					}
				});
				utils.each(mergeTds, function(td) {
					td.rowSpan--
				});
				row.parentNode.removeChild(row);
				this.update()
			},
			insertCol: function(colIndex, sourceCell, defaultValue) {
				var rowsNum = this.rowsNum,
					rowIndex = 0,
					tableRow, cell, backWidth = parseInt((this.table.offsetWidth - (this.colsNum + 1) *
						20 - (this.colsNum + 1)) / (this.colsNum + 1), 10),
					isInsertTitleCol = typeof sourceCell == "string" && sourceCell.toUpperCase() ==
					"TH";

				function replaceTdToTh(rowIndex, cell, tableRow) {
					if (rowIndex == 0) {
						var th = cell.nextSibling || cell.previousSibling;
						if (th.tagName == "TH") {
							th = cell.ownerDocument.createElement("th");
							th.appendChild(cell.firstChild);
							tableRow.insertBefore(th, cell);
							domUtils.remove(cell)
						}
					} else {
						if (cell.tagName == "TH") {
							var td = cell.ownerDocument.createElement("td");
							td.appendChild(cell.firstChild);
							tableRow.insertBefore(td, cell);
							domUtils.remove(cell)
						}
					}
				}
				var preCell;
				if (colIndex == 0 || colIndex == this.colsNum) {
					for (; rowIndex < rowsNum; rowIndex++) {
						tableRow = this.table.rows[rowIndex];
						preCell = tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length];
						cell = this.cloneCell(sourceCell, true);
						this.setCellContent(cell);
						cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
						preCell && cell.setAttribute("width", preCell.getAttribute("width"));
						if (!colIndex) {
							tableRow.insertBefore(cell, tableRow.cells[0])
						} else {
							domUtils.insertAfter(tableRow.cells[tableRow.cells.length - 1], cell)
						}
						if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow)
					}
				} else {
					for (; rowIndex < rowsNum; rowIndex++) {
						var cellInfo = this.indexTable[rowIndex][colIndex];
						if (cellInfo.colIndex < colIndex) {
							cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
							cell.colSpan = cellInfo.colSpan + 1
						} else {
							tableRow = this.table.rows[rowIndex];
							preCell = tableRow.cells[cellInfo.cellIndex];
							cell = this.cloneCell(sourceCell, true);
							this.setCellContent(cell);
							cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
							preCell && cell.setAttribute("width", preCell.getAttribute("width"));
							preCell ? tableRow.insertBefore(cell, preCell) : tableRow.appendChild(cell)
						}
						if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow)
					}
				}
				this.update();
				this.updateWidth(backWidth, defaultValue || {
					tdPadding: 10,
					tdBorder: 1
				})
			},
			updateWidth: function(width, defaultValue) {
				var table = this.table,
					tmpWidth = UETable.getWidth(table) - defaultValue.tdPadding * 2 - defaultValue
					.tdBorder + width;
				if (tmpWidth < table.ownerDocument.body.offsetWidth) {
					table.setAttribute("width", tmpWidth);
					return
				}
				var tds = domUtils.getElementsByTagName(this.table, "td th");
				utils.each(tds, function(td) {
					td.setAttribute("width", width)
				})
			},
			deleteCol: function(colIndex) {
				var indexTable = this.indexTable,
					tableRows = this.table.rows,
					backTableWidth = this.table.getAttribute("width"),
					backTdWidth = 0,
					rowsNum = this.rowsNum,
					cacheMap = {};
				for (var rowIndex = 0; rowIndex < rowsNum;) {
					var infoRow = indexTable[rowIndex],
						cellInfo = infoRow[colIndex],
						key = cellInfo.rowIndex + "_" + cellInfo.colIndex;
					if (cacheMap[key]) continue;
					cacheMap[key] = 1;
					var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
					if (!backTdWidth) backTdWidth = cell && parseInt(cell.offsetWidth / cell.colSpan,
						10).toFixed(0);
					if (cell.colSpan > 1) {
						cell.colSpan--
					} else {
						tableRows[rowIndex].deleteCell(cellInfo.cellIndex)
					}
					rowIndex += cellInfo.rowSpan || 1
				}
				this.table.setAttribute("width", backTableWidth - backTdWidth);
				this.update()
			},
			splitToCells: function(cell) {
				var me = this,
					cells = this.splitToRows(cell);
				utils.each(cells, function(cell) {
					me.splitToCols(cell)
				})
			},
			splitToRows: function(cell) {
				var cellInfo = this.getCellInfo(cell),
					rowIndex = cellInfo.rowIndex,
					colIndex = cellInfo.colIndex,
					results = [];
				cell.rowSpan = 1;
				results.push(cell);
				for (var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan; i < endRow; i++) {
					if (i == rowIndex) continue;
					var tableRow = this.table.rows[i],
						tmpCell = tableRow.insertCell(colIndex - this.getPreviewMergedCellsNum(i,
							colIndex));
					tmpCell.colSpan = cellInfo.colSpan;
					this.setCellContent(tmpCell);
					tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
					tmpCell.setAttribute("align", cell.getAttribute("align"));
					if (cell.style.cssText) {
						tmpCell.style.cssText = cell.style.cssText
					}
					results.push(tmpCell)
				}
				this.update();
				return results
			},
			getPreviewMergedCellsNum: function(rowIndex, colIndex) {
				var indexRow = this.indexTable[rowIndex],
					num = 0;
				for (var i = 0; i < colIndex;) {
					var colSpan = indexRow[i].colSpan,
						tmpRowIndex = indexRow[i].rowIndex;
					num += colSpan - (tmpRowIndex == rowIndex ? 1 : 0);
					i += colSpan
				}
				return num
			},
			splitToCols: function(cell) {
				var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
					cellInfo = this.getCellInfo(cell),
					rowIndex = cellInfo.rowIndex,
					colIndex = cellInfo.colIndex,
					results = [];
				cell.colSpan = 1;
				cell.setAttribute("width", backWidth);
				results.push(cell);
				for (var j = colIndex, endCol = colIndex + cellInfo.colSpan; j < endCol; j++) {
					if (j == colIndex) continue;
					var tableRow = this.table.rows[rowIndex],
						tmpCell = tableRow.insertCell(this.indexTable[rowIndex][j].cellIndex + 1);
					tmpCell.rowSpan = cellInfo.rowSpan;
					this.setCellContent(tmpCell);
					tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
					tmpCell.setAttribute("align", cell.getAttribute("align"));
					tmpCell.setAttribute("width", backWidth);
					if (cell.style.cssText) {
						tmpCell.style.cssText = cell.style.cssText
					}
					if (cell.tagName == "TH") {
						var th = cell.ownerDocument.createElement("th");
						th.appendChild(tmpCell.firstChild);
						th.setAttribute("vAlign", cell.getAttribute("vAlign"));
						th.rowSpan = tmpCell.rowSpan;
						tableRow.insertBefore(th, tmpCell);
						domUtils.remove(tmpCell)
					}
					results.push(tmpCell)
				}
				this.update();
				return results
			},
			isLastCell: function(cell, rowsNum, colsNum) {
				rowsNum = rowsNum || this.rowsNum;
				colsNum = colsNum || this.colsNum;
				var cellInfo = this.getCellInfo(cell);
				return cellInfo.rowIndex + cellInfo.rowSpan == rowsNum && cellInfo.colIndex + cellInfo
					.colSpan == colsNum
			},
			getLastCell: function(cells) {
				cells = cells || this.table.getElementsByTagName("td");
				var firstInfo = this.getCellInfo(cells[0]);
				var me = this,
					last = cells[0],
					tr = last.parentNode,
					cellsNum = 0,
					cols = 0,
					rows;
				utils.each(cells, function(cell) {
					if (cell.parentNode == tr) cols += cell.colSpan || 1;
					cellsNum += cell.rowSpan * cell.colSpan || 1
				});
				rows = cellsNum / cols;
				utils.each(cells, function(cell) {
					if (me.isLastCell(cell, rows, cols)) {
						last = cell;
						return false
					}
				});
				return last
			},
			selectRow: function(rowIndex) {
				var indexRow = this.indexTable[rowIndex],
					start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
					end = this.getCell(indexRow[this.colsNum - 1].rowIndex, indexRow[this.colsNum - 1]
						.cellIndex),
					range = this.getCellsRange(start, end);
				this.setSelected(range)
			},
			selectTable: function() {
				var tds = this.table.getElementsByTagName("td"),
					range = this.getCellsRange(tds[0], tds[tds.length - 1]);
				this.setSelected(range)
			},
			setBackground: function(cells, value) {
				if (typeof value === "string") {
					utils.each(cells, function(cell) {
						cell.style.backgroundColor = value
					})
				} else if (typeof value === "object") {
					value = utils.extend({
						repeat: true,
						colorList: ["#ddd", "#fff"]
					}, value);
					var rowIndex = this.getCellInfo(cells[0]).rowIndex,
						count = 0,
						colors = value.colorList,
						getColor = function(list, index, repeat) {
							return list[index] ? list[index] : repeat ? list[index % list.length] : ""
						};
					for (var i = 0, cell; cell = cells[i++];) {
						var cellInfo = this.getCellInfo(cell);
						cell.style.backgroundColor = getColor(colors, rowIndex + count == cellInfo
							.rowIndex ? count : ++count, value.repeat)
					}
				}
			},
			removeBackground: function(cells) {
				utils.each(cells, function(cell) {
					cell.style.backgroundColor = ""
				})
			}
		};

		function showError(e) {}
	})();
	(function() {
		var UT = UE.UETable,
			getTableItemsByRange = function(editor) {
				return UT.getTableItemsByRange(editor)
			},
			getUETableBySelected = function(editor) {
				return UT.getUETableBySelected(editor)
			},
			getDefaultValue = function(editor, table) {
				return UT.getDefaultValue(editor, table)
			},
			getUETable = function(tdOrTable) {
				return UT.getUETable(tdOrTable)
			};
		UE.commands["inserttable"] = {
			queryCommandState: function() {
				return getTableItemsByRange(this).table ? -1 : 0
			},
			execCommand: function(cmd, opt) {
				function createTable(opt, tdWidth) {
					var html = [],
						rowsNum = opt.numRows,
						colsNum = opt.numCols;
					for (var r = 0; r < rowsNum; r++) {
						html.push("<tr" + (r == 0 ? ' class="firstRow"' : "") + ">");
						for (var c = 0; c < colsNum; c++) {
							html.push('<td width="' + tdWidth + '"  vAlign="' + opt.tdvalign + '" >' + (
								browser.ie && browser.version < 11 ? domUtils.fillChar : "<br/>"
								) + "</td>")
						}
						html.push("</tr>")
					}
					return "<table><tbody>" + html.join("") + "</tbody></table>"
				}
				if (!opt) {
					opt = utils.extend({}, {
						numCols: this.options.defaultCols,
						numRows: this.options.defaultRows,
						tdvalign: this.options.tdvalign
					})
				}
				var me = this;
				var range = this.selection.getRange(),
					start = range.startContainer,
					firstParentBlock = domUtils.findParent(start, function(node) {
						return domUtils.isBlockElm(node)
					}, true) || me.body;
				var defaultValue = getDefaultValue(me),
					tableWidth = firstParentBlock.offsetWidth,
					tdWidth = Math.floor(tableWidth / opt.numCols - defaultValue.tdPadding * 2 -
						defaultValue.tdBorder);
				!opt.tdvalign && (opt.tdvalign = me.options.tdvalign);
				me.execCommand("inserthtml", createTable(opt, tdWidth))
			}
		};
		UE.commands["insertparagraphbeforetable"] = {
			queryCommandState: function() {
				return getTableItemsByRange(this).cell ? 0 : -1
			},
			execCommand: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					var p = this.document.createElement("p");
					p.innerHTML = browser.ie ? "&nbsp;" : "<br />";
					table.parentNode.insertBefore(p, table);
					this.selection.getRange().setStart(p, 0).setCursor()
				}
			}
		};
		UE.commands["deletetable"] = {
			queryCommandState: function() {
				var rng = this.selection.getRange();
				return domUtils.findParentByTagName(rng.startContainer, "table", true) ? 0 : -1
			},
			execCommand: function(cmd, table) {
				var rng = this.selection.getRange();
				table = table || domUtils.findParentByTagName(rng.startContainer, "table", true);
				if (table) {
					var next = table.nextSibling;
					if (!next) {
						next = domUtils.createElement(this.document, "p", {
							innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
						});
						table.parentNode.insertBefore(next, table)
					}
					domUtils.remove(table);
					rng = this.selection.getRange();
					if (next.nodeType == 3) {
						rng.setStartBefore(next)
					} else {
						rng.setStart(next, 0)
					}
					rng.setCursor(false, true);
					this.fireEvent("tablehasdeleted")
				}
			}
		};
		UE.commands["cellalign"] = {
			queryCommandState: function() {
				return getSelectedArr(this).length ? 0 : -1
			},
			execCommand: function(cmd, align) {
				var selectedTds = getSelectedArr(this);
				if (selectedTds.length) {
					for (var i = 0, ci; ci = selectedTds[i++];) {
						ci.setAttribute("align", align)
					}
				}
			}
		};
		UE.commands["cellvalign"] = {
			queryCommandState: function() {
				return getSelectedArr(this).length ? 0 : -1
			},
			execCommand: function(cmd, valign) {
				var selectedTds = getSelectedArr(this);
				if (selectedTds.length) {
					for (var i = 0, ci; ci = selectedTds[i++];) {
						ci.setAttribute("vAlign", valign)
					}
				}
			}
		};
		UE.commands["insertcaption"] = {
			queryCommandState: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					return table.getElementsByTagName("caption").length == 0 ? 1 : -1
				}
				return -1
			},
			execCommand: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					var caption = this.document.createElement("caption");
					caption.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
					table.insertBefore(caption, table.firstChild);
					var range = this.selection.getRange();
					range.setStart(caption, 0).setCursor()
				}
			}
		};
		UE.commands["deletecaption"] = {
			queryCommandState: function() {
				var rng = this.selection.getRange(),
					table = domUtils.findParentByTagName(rng.startContainer, "table");
				if (table) {
					return table.getElementsByTagName("caption").length == 0 ? -1 : 1
				}
				return -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					table = domUtils.findParentByTagName(rng.startContainer, "table");
				if (table) {
					domUtils.remove(table.getElementsByTagName("caption")[0]);
					var range = this.selection.getRange();
					range.setStart(table.rows[0].cells[0], 0).setCursor()
				}
			}
		};
		UE.commands["inserttitle"] = {
			queryCommandState: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					var firstRow = table.rows[0];
					return firstRow.cells[firstRow.cells.length - 1].tagName.toLowerCase() != "th" ? 0 :
						-1
				}
				return -1
			},
			execCommand: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					getUETable(table).insertRow(0, "th")
				}
				var th = table.getElementsByTagName("th")[0];
				this.selection.getRange().setStart(th, 0).setCursor(false, true)
			}
		};
		UE.commands["deletetitle"] = {
			queryCommandState: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					var firstRow = table.rows[0];
					return firstRow.cells[firstRow.cells.length - 1].tagName.toLowerCase() == "th" ? 0 :
						-1
				}
				return -1
			},
			execCommand: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					domUtils.remove(table.rows[0])
				}
				var td = table.getElementsByTagName("td")[0];
				this.selection.getRange().setStart(td, 0).setCursor(false, true)
			}
		};
		UE.commands["inserttitlecol"] = {
			queryCommandState: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					var lastRow = table.rows[table.rows.length - 1];
					return lastRow.getElementsByTagName("th").length ? -1 : 0
				}
				return -1
			},
			execCommand: function(cmd) {
				var table = getTableItemsByRange(this).table;
				if (table) {
					getUETable(table).insertCol(0, "th")
				}
				resetTdWidth(table, this);
				var th = table.getElementsByTagName("th")[0];
				this.selection.getRange().setStart(th, 0).setCursor(false, true)
			}
		};
		UE.commands["deletetitlecol"] = {
			queryCommandState: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					var lastRow = table.rows[table.rows.length - 1];
					return lastRow.getElementsByTagName("th").length ? 0 : -1
				}
				return -1
			},
			execCommand: function() {
				var table = getTableItemsByRange(this).table;
				if (table) {
					for (var i = 0; i < table.rows.length; i++) {
						domUtils.remove(table.rows[i].children[0])
					}
				}
				resetTdWidth(table, this);
				var td = table.getElementsByTagName("td")[0];
				this.selection.getRange().setStart(td, 0).setCursor(false, true)
			}
		};
		UE.commands["mergeright"] = {
			queryCommandState: function(cmd) {
				var tableItems = getTableItemsByRange(this),
					table = tableItems.table,
					cell = tableItems.cell;
				if (!table || !cell) return -1;
				var ut = getUETable(table);
				if (ut.selectedTds.length) return -1;
				var cellInfo = ut.getCellInfo(cell),
					rightColIndex = cellInfo.colIndex + cellInfo.colSpan;
				if (rightColIndex >= ut.colsNum) return -1;
				var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
					rightCell = table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex];
				if (!rightCell || cell.tagName != rightCell.tagName) return -1;
				return rightCellInfo.rowIndex == cellInfo.rowIndex && rightCellInfo.rowSpan == cellInfo
					.rowSpan ? 0 : -1
			},
			execCommand: function(cmd) {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell);
				ut.mergeRight(cell);
				rng.moveToBookmark(bk).select()
			}
		};
		UE.commands["mergedown"] = {
			queryCommandState: function(cmd) {
				var tableItems = getTableItemsByRange(this),
					table = tableItems.table,
					cell = tableItems.cell;
				if (!table || !cell) return -1;
				var ut = getUETable(table);
				if (ut.selectedTds.length) return -1;
				var cellInfo = ut.getCellInfo(cell),
					downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan;
				if (downRowIndex >= ut.rowsNum) return -1;
				var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
					downCell = table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex];
				if (!downCell || cell.tagName != downCell.tagName) return -1;
				return downCellInfo.colIndex == cellInfo.colIndex && downCellInfo.colSpan == cellInfo
					.colSpan ? 0 : -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell);
				ut.mergeDown(cell);
				rng.moveToBookmark(bk).select()
			}
		};
		UE.commands["mergecells"] = {
			queryCommandState: function() {
				return getUETableBySelected(this) ? 0 : -1
			},
			execCommand: function() {
				var ut = getUETableBySelected(this);
				if (ut && ut.selectedTds.length) {
					var cell = ut.selectedTds[0];
					ut.mergeRange();
					var rng = this.selection.getRange();
					if (domUtils.isEmptyBlock(cell)) {
						rng.setStart(cell, 0).collapse(true)
					} else {
						rng.selectNodeContents(cell)
					}
					rng.select()
				}
			}
		};
		UE.commands["insertrow"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell;
				return cell && (cell.tagName == "TD" || cell.tagName == "TH" && tableItems.tr !==
						tableItems.table.rows[0]) && getUETable(tableItems.table).rowsNum < this.options
					.maxRowNum ? 0 : -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell,
					table = tableItems.table,
					ut = getUETable(table),
					cellInfo = ut.getCellInfo(cell);
				if (!ut.selectedTds.length) {
					ut.insertRow(cellInfo.rowIndex, cell)
				} else {
					var range = ut.cellsRange;
					for (var i = 0, len = range.endRowIndex - range.beginRowIndex + 1; i < len; i++) {
						ut.insertRow(range.beginRowIndex, cell)
					}
				}
				rng.moveToBookmark(bk).select();
				if (table.getAttribute("interlaced") === "enabled") this.fireEvent("interlacetable",
					table)
			}
		};
		UE.commands["insertrownext"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell;
				return cell && cell.tagName == "TD" && getUETable(tableItems.table).rowsNum < this
					.options.maxRowNum ? 0 : -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell,
					table = tableItems.table,
					ut = getUETable(table),
					cellInfo = ut.getCellInfo(cell);
				if (!ut.selectedTds.length) {
					ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell)
				} else {
					var range = ut.cellsRange;
					for (var i = 0, len = range.endRowIndex - range.beginRowIndex + 1; i < len; i++) {
						ut.insertRow(range.endRowIndex + 1, cell)
					}
				}
				rng.moveToBookmark(bk).select();
				if (table.getAttribute("interlaced") === "enabled") this.fireEvent("interlacetable",
					table)
			}
		};
		UE.commands["deleterow"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this);
				return tableItems.cell ? 0 : -1
			},
			execCommand: function() {
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell),
					cellsRange = ut.cellsRange,
					cellInfo = ut.getCellInfo(cell),
					preCell = ut.getVSideCell(cell),
					nextCell = ut.getVSideCell(cell, true),
					rng = this.selection.getRange();
				if (utils.isEmptyObject(cellsRange)) {
					ut.deleteRow(cellInfo.rowIndex)
				} else {
					for (var i = cellsRange.beginRowIndex; i < cellsRange.endRowIndex + 1; i++) {
						ut.deleteRow(cellsRange.beginRowIndex)
					}
				}
				var table = ut.table;
				if (!table.getElementsByTagName("td").length) {
					var nextSibling = table.nextSibling;
					domUtils.remove(table);
					if (nextSibling) {
						rng.setStart(nextSibling, 0).setCursor(false, true)
					}
				} else {
					if (cellInfo.rowSpan == 1 || cellInfo.rowSpan == cellsRange.endRowIndex - cellsRange
						.beginRowIndex + 1) {
						if (nextCell || preCell) rng.selectNodeContents(nextCell || preCell).setCursor(
							false, true)
					} else {
						var newCell = ut.getCell(cellInfo.rowIndex, ut.indexTable[cellInfo.rowIndex][
							cellInfo.colIndex
						].cellIndex);
						if (newCell) rng.selectNodeContents(newCell).setCursor(false, true)
					}
				}
				if (table.getAttribute("interlaced") === "enabled") this.fireEvent("interlacetable",
					table)
			}
		};
		UE.commands["insertcol"] = {
			queryCommandState: function(cmd) {
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell;
				return cell && (cell.tagName == "TD" || cell.tagName == "TH" && cell !== tableItems.tr
						.cells[0]) && getUETable(tableItems.table).colsNum < this.options.maxColNum ?
					0 : -1
			},
			execCommand: function(cmd) {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				if (this.queryCommandState(cmd) == -1) return;
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell),
					cellInfo = ut.getCellInfo(cell);
				if (!ut.selectedTds.length) {
					ut.insertCol(cellInfo.colIndex, cell)
				} else {
					var range = ut.cellsRange;
					for (var i = 0, len = range.endColIndex - range.beginColIndex + 1; i < len; i++) {
						ut.insertCol(range.beginColIndex, cell)
					}
				}
				rng.moveToBookmark(bk).select(true)
			}
		};
		UE.commands["insertcolnext"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell;
				return cell && getUETable(tableItems.table).colsNum < this.options.maxColNum ? 0 : -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell),
					cellInfo = ut.getCellInfo(cell);
				if (!ut.selectedTds.length) {
					ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell)
				} else {
					var range = ut.cellsRange;
					for (var i = 0, len = range.endColIndex - range.beginColIndex + 1; i < len; i++) {
						ut.insertCol(range.endColIndex + 1, cell)
					}
				}
				rng.moveToBookmark(bk).select()
			}
		};
		UE.commands["deletecol"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this);
				return tableItems.cell ? 0 : -1
			},
			execCommand: function() {
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell),
					range = ut.cellsRange,
					cellInfo = ut.getCellInfo(cell),
					preCell = ut.getHSideCell(cell),
					nextCell = ut.getHSideCell(cell, true);
				if (utils.isEmptyObject(range)) {
					ut.deleteCol(cellInfo.colIndex)
				} else {
					for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
						ut.deleteCol(range.beginColIndex)
					}
				}
				var table = ut.table,
					rng = this.selection.getRange();
				if (!table.getElementsByTagName("td").length) {
					var nextSibling = table.nextSibling;
					domUtils.remove(table);
					if (nextSibling) {
						rng.setStart(nextSibling, 0).setCursor(false, true)
					}
				} else {
					if (domUtils.inDoc(cell, this.document)) {
						rng.setStart(cell, 0).setCursor(false, true)
					} else {
						if (nextCell && domUtils.inDoc(nextCell, this.document)) {
							rng.selectNodeContents(nextCell).setCursor(false, true)
						} else {
							if (preCell && domUtils.inDoc(preCell, this.document)) {
								rng.selectNodeContents(preCell).setCursor(true, true)
							}
						}
					}
				}
			}
		};
		UE.commands["splittocells"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell;
				if (!cell) return -1;
				var ut = getUETable(tableItems.table);
				if (ut.selectedTds.length > 0) return -1;
				return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell);
				ut.splitToCells(cell);
				rng.moveToBookmark(bk).select()
			}
		};
		UE.commands["splittorows"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell;
				if (!cell) return -1;
				var ut = getUETable(tableItems.table);
				if (ut.selectedTds.length > 0) return -1;
				return cell && cell.rowSpan > 1 ? 0 : -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell);
				ut.splitToRows(cell);
				rng.moveToBookmark(bk).select()
			}
		};
		UE.commands["splittocols"] = {
			queryCommandState: function() {
				var tableItems = getTableItemsByRange(this),
					cell = tableItems.cell;
				if (!cell) return -1;
				var ut = getUETable(tableItems.table);
				if (ut.selectedTds.length > 0) return -1;
				return cell && cell.colSpan > 1 ? 0 : -1
			},
			execCommand: function() {
				var rng = this.selection.getRange(),
					bk = rng.createBookmark(true);
				var cell = getTableItemsByRange(this).cell,
					ut = getUETable(cell);
				ut.splitToCols(cell);
				rng.moveToBookmark(bk).select()
			}
		};
		UE.commands["adaptbytext"] = UE.commands["adaptbywindow"] = {
			queryCommandState: function() {
				return getTableItemsByRange(this).table ? 0 : -1
			},
			execCommand: function(cmd) {
				var tableItems = getTableItemsByRange(this),
					table = tableItems.table;
				if (table) {
					if (cmd == "adaptbywindow") {
						resetTdWidth(table, this)
					} else {
						var cells = domUtils.getElementsByTagName(table, "td th");
						utils.each(cells, function(cell) {
							cell.removeAttribute("width")
						});
						table.removeAttribute("width")
					}
				}
			}
		};
		UE.commands["averagedistributecol"] = {
			queryCommandState: function() {
				var ut = getUETableBySelected(this);
				if (!ut) return -1;
				return ut.isFullRow() || ut.isFullCol() ? 0 : -1
			},
			execCommand: function(cmd) {
				var me = this,
					ut = getUETableBySelected(me);

				function getAverageWidth() {
					var tb = ut.table,
						averageWidth, sumWidth = 0,
						colsNum = 0,
						tbAttr = getDefaultValue(me, tb);
					if (ut.isFullRow()) {
						sumWidth = tb.offsetWidth;
						colsNum = ut.colsNum
					} else {
						var begin = ut.cellsRange.beginColIndex,
							end = ut.cellsRange.endColIndex,
							node;
						for (var i = begin; i <= end;) {
							node = ut.selectedTds[i];
							sumWidth += node.offsetWidth;
							i += node.colSpan;
							colsNum += 1
						}
					}
					averageWidth = Math.ceil(sumWidth / colsNum) - tbAttr.tdBorder * 2 - tbAttr
						.tdPadding * 2;
					return averageWidth
				}

				function setAverageWidth(averageWidth) {
					utils.each(domUtils.getElementsByTagName(ut.table, "th"), function(node) {
						node.setAttribute("width", "")
					});
					var cells = ut.isFullRow() ? domUtils.getElementsByTagName(ut.table, "td") : ut
						.selectedTds;
					utils.each(cells, function(node) {
						if (node.colSpan == 1) {
							node.setAttribute("width", averageWidth)
						}
					})
				}
				if (ut && ut.selectedTds.length) {
					setAverageWidth(getAverageWidth())
				}
			}
		};
		UE.commands["averagedistributerow"] = {
			queryCommandState: function() {
				var ut = getUETableBySelected(this);
				if (!ut) return -1;
				if (ut.selectedTds && /th/gi.test(ut.selectedTds[0].tagName)) return -1;
				return ut.isFullRow() || ut.isFullCol() ? 0 : -1
			},
			execCommand: function(cmd) {
				var me = this,
					ut = getUETableBySelected(me);

				function getAverageHeight() {
					var averageHeight, rowNum, sumHeight = 0,
						tb = ut.table,
						tbAttr = getDefaultValue(me, tb),
						tdpadding = parseInt(domUtils.getComputedStyle(tb.getElementsByTagName("td")[0],
							"padding-top"));
					if (ut.isFullCol()) {
						var captionArr = domUtils.getElementsByTagName(tb, "caption"),
							thArr = domUtils.getElementsByTagName(tb, "th"),
							captionHeight, thHeight;
						if (captionArr.length > 0) {
							captionHeight = captionArr[0].offsetHeight
						}
						if (thArr.length > 0) {
							thHeight = thArr[0].offsetHeight
						}
						sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0);
						rowNum = thArr.length == 0 ? ut.rowsNum : ut.rowsNum - 1
					} else {
						var begin = ut.cellsRange.beginRowIndex,
							end = ut.cellsRange.endRowIndex,
							count = 0,
							trs = domUtils.getElementsByTagName(tb, "tr");
						for (var i = begin; i <= end; i++) {
							sumHeight += trs[i].offsetHeight;
							count += 1
						}
						rowNum = count
					}
					if (browser.ie && browser.version < 9) {
						averageHeight = Math.ceil(sumHeight / rowNum)
					} else {
						averageHeight = Math.ceil(sumHeight / rowNum) - tbAttr.tdBorder * 2 -
							tdpadding * 2
					}
					return averageHeight
				}

				function setAverageHeight(averageHeight) {
					var cells = ut.isFullCol() ? domUtils.getElementsByTagName(ut.table, "td") : ut
						.selectedTds;
					utils.each(cells, function(node) {
						if (node.rowSpan == 1) {
							node.setAttribute("height", averageHeight)
						}
					})
				}
				if (ut && ut.selectedTds.length) {
					setAverageHeight(getAverageHeight())
				}
			}
		};
		UE.commands["cellalignment"] = {
			queryCommandState: function() {
				return getTableItemsByRange(this).table ? 0 : -1
			},
			execCommand: function(cmd, data) {
				var me = this,
					ut = getUETableBySelected(me);
				if (!ut) {
					var start = me.selection.getStart(),
						cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"],
							true);
					if (!/caption/gi.test(cell.tagName)) {
						domUtils.setAttributes(cell, data)
					} else {
						cell.style.textAlign = data.align;
						cell.style.verticalAlign = data.vAlign
					}
					me.selection.getRange().setCursor(true)
				} else {
					utils.each(ut.selectedTds, function(cell) {
						domUtils.setAttributes(cell, data)
					})
				}
			},
			queryCommandValue: function(cmd) {
				var activeMenuCell = getTableItemsByRange(this).cell;
				if (!activeMenuCell) {
					activeMenuCell = getSelectedArr(this)[0]
				}
				if (!activeMenuCell) {
					return null
				} else {
					var cells = UE.UETable.getUETable(activeMenuCell).selectedTds;
					!cells.length && (cells = activeMenuCell);
					return UE.UETable.getTableCellAlignState(cells)
				}
			}
		};
		UE.commands["tablealignment"] = {
			queryCommandState: function() {
				if (browser.ie && browser.version < 8) {
					return -1
				}
				return getTableItemsByRange(this).table ? 0 : -1
			},
			execCommand: function(cmd, value) {
				var me = this,
					start = me.selection.getStart(),
					table = start && domUtils.findParentByTagName(start, ["table"], true);
				if (table) {
					table.setAttribute("align", value)
				}
			}
		};
		UE.commands["edittable"] = {
			queryCommandState: function() {
				return getTableItemsByRange(this).table ? 0 : -1
			},
			execCommand: function(cmd, color) {
				var rng = this.selection.getRange(),
					table = domUtils.findParentByTagName(rng.startContainer, "table");
				if (table) {
					var arr = domUtils.getElementsByTagName(table, "td").concat(domUtils
						.getElementsByTagName(table, "th"), domUtils.getElementsByTagName(table,
							"caption"));
					utils.each(arr, function(node) {
						node.style.borderColor = color
					})
				}
			}
		};
		UE.commands["edittd"] = {
			queryCommandState: function() {
				return getTableItemsByRange(this).table ? 0 : -1
			},
			execCommand: function(cmd, bkColor) {
				var me = this,
					ut = getUETableBySelected(me);
				if (!ut) {
					var start = me.selection.getStart(),
						cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"],
							true);
					if (cell) {
						cell.style.backgroundColor = bkColor
					}
				} else {
					utils.each(ut.selectedTds, function(cell) {
						cell.style.backgroundColor = bkColor
					})
				}
			}
		};
		UE.commands["settablebackground"] = {
			queryCommandState: function() {
				return getSelectedArr(this).length > 1 ? 0 : -1
			},
			execCommand: function(cmd, value) {
				var cells, ut;
				cells = getSelectedArr(this);
				ut = getUETable(cells[0]);
				ut.setBackground(cells, value)
			}
		};
		UE.commands["cleartablebackground"] = {
			queryCommandState: function() {
				var cells = getSelectedArr(this);
				if (!cells.length) return -1;
				for (var i = 0, cell; cell = cells[i++];) {
					if (cell.style.backgroundColor !== "") return 0
				}
				return -1
			},
			execCommand: function() {
				var cells = getSelectedArr(this),
					ut = getUETable(cells[0]);
				ut.removeBackground(cells)
			}
		};
		UE.commands["interlacetable"] = UE.commands["uninterlacetable"] = {
			queryCommandState: function(cmd) {
				var table = getTableItemsByRange(this).table;
				if (!table) return -1;
				var interlaced = table.getAttribute("interlaced");
				if (cmd == "interlacetable") {
					return interlaced === "enabled" ? -1 : 0
				} else {
					return !interlaced || interlaced === "disabled" ? -1 : 0
				}
			},
			execCommand: function(cmd, classList) {
				var table = getTableItemsByRange(this).table;
				if (cmd == "interlacetable") {
					table.setAttribute("interlaced", "enabled");
					this.fireEvent("interlacetable", table, classList)
				} else {
					table.setAttribute("interlaced", "disabled");
					this.fireEvent("uninterlacetable", table)
				}
			}
		};
		UE.commands["setbordervisible"] = {
			queryCommandState: function(cmd) {
				var table = getTableItemsByRange(this).table;
				if (!table) return -1;
				return 0
			},
			execCommand: function() {
				var table = getTableItemsByRange(this).table;
				utils.each(domUtils.getElementsByTagName(table, "td"), function(td) {
					td.style.borderWidth = "1px";
					td.style.borderStyle = "solid"
				})
			}
		};

		function resetTdWidth(table, editor) {
			var tds = domUtils.getElementsByTagName(table, "td th");
			utils.each(tds, function(td) {
				td.removeAttribute("width")
			});
			table.setAttribute("width", getTableWidth(editor, true, getDefaultValue(editor, table)));
			var tdsWidths = [];
			setTimeout(function() {
				utils.each(tds, function(td) {
					td.colSpan == 1 && tdsWidths.push(td.offsetWidth)
				});
				utils.each(tds, function(td, i) {
					td.colSpan == 1 && td.setAttribute("width", tdsWidths[i] + "")
				})
			}, 0)
		}

		function getTableWidth(editor, needIEHack, defaultValue) {
			var body = editor.body;
			return body.offsetWidth - (needIEHack ? parseInt(domUtils.getComputedStyle(body, "margin-left"),
				10) * 2 : 0) - defaultValue.tableBorder * 2 - (editor.options.offsetWidth || 0)
		}

		function getSelectedArr(editor) {
			var cell = getTableItemsByRange(editor).cell;
			if (cell) {
				var ut = getUETable(cell);
				return ut.selectedTds.length ? ut.selectedTds : [cell]
			} else {
				return []
			}
		}
	})();
	UE.plugins["table"] = function() {
		var me = this,
			tabTimer = null,
			tableDragTimer = null,
			tableResizeTimer = null,
			cellMinWidth = 5,
			isInResizeBuffer = false,
			cellBorderWidth = 5,
			offsetOfTableCell = 10,
			singleClickState = 0,
			userActionStatus = null,
			dblclickTime = 200,
			UT = UE.UETable,
			getUETable = function(tdOrTable) {
				return UT.getUETable(tdOrTable)
			},
			getUETableBySelected = function(editor) {
				return UT.getUETableBySelected(editor)
			},
			getDefaultValue = function(editor, table) {
				return UT.getDefaultValue(editor, table)
			},
			removeSelectedClass = function(cells) {
				return UT.removeSelectedClass(cells)
			};

		function showError(e) {}
		me.ready(function() {
			var me = this;
			var orgGetText = me.selection.getText;
			me.selection.getText = function() {
				var table = getUETableBySelected(me);
				if (table) {
					var str = "";
					utils.each(table.selectedTds, function(td) {
						str += td[browser.ie ? "innerText" : "textContent"]
					});
					return str
				} else {
					return orgGetText.call(me.selection)
				}
			}
		});
		var startTd = null,
			currentTd = null,
			onDrag = "",
			onBorder = false,
			dragButton = null,
			dragOver = false,
			dragLine = null,
			dragTd = null;
		var mousedown = false,
			needIEHack = true;
		me.setOpt({
			maxColNum: 20,
			maxRowNum: 100,
			defaultCols: 5,
			defaultRows: 5,
			tdvalign: "top",
			cursorpath: me.options.UEDITOR_HOME_URL + "themes/default/images/cursor_",
			tableDragable: false,
			classList: ["ue-table-interlace-color-single", "ue-table-interlace-color-double"]
		});
		me.getUETable = getUETable;
		var commands = {
			deletetable: 1,
			inserttable: 1,
			cellvalign: 1,
			insertcaption: 1,
			deletecaption: 1,
			inserttitle: 1,
			deletetitle: 1,
			mergeright: 1,
			mergedown: 1,
			mergecells: 1,
			insertrow: 1,
			insertrownext: 1,
			deleterow: 1,
			insertcol: 1,
			insertcolnext: 1,
			deletecol: 1,
			splittocells: 1,
			splittorows: 1,
			splittocols: 1,
			adaptbytext: 1,
			adaptbywindow: 1,
			adaptbycustomer: 1,
			insertparagraph: 1,
			insertparagraphbeforetable: 1,
			averagedistributecol: 1,
			averagedistributerow: 1
		};
		me.ready(function() {
			utils.cssRule("table", ".selectTdClass{background-color:#edf5fa !important}" +
				"table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}" +
				"table{margin-bottom:10px;border-collapse:collapse;display:table;}" +
				"td,th{padding: 5px 10px;border: 1px solid #DDD;}" +
				"caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}" +
				"th{border-top:1px solid #BBB;background-color:#F7F7F7;}" +
				"table tr.firstRow th{border-top-width:2px;}" +
				".ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }" +
				"td p{margin:0;padding:0;}", me.document);
			var tableCopyList, isFullCol, isFullRow;
			me.addListener("keydown", function(cmd, evt) {
				var me = this;
				var keyCode = evt.keyCode || evt.which;
				if (keyCode == 8) {
					var ut = getUETableBySelected(me);
					if (ut && ut.selectedTds.length) {
						if (ut.isFullCol()) {
							me.execCommand("deletecol")
						} else if (ut.isFullRow()) {
							me.execCommand("deleterow")
						} else {
							me.fireEvent("delcells")
						}
						domUtils.preventDefault(evt)
					}
					var caption = domUtils.findParentByTagName(me.selection.getStart(),
							"caption", true),
						range = me.selection.getRange();
					if (range.collapsed && caption && isEmptyBlock(caption)) {
						me.fireEvent("saveScene");
						var table = caption.parentNode;
						domUtils.remove(caption);
						if (table) {
							range.setStart(table.rows[0].cells[0], 0).setCursor(false, true)
						}
						me.fireEvent("saveScene")
					}
				}
				if (keyCode == 46) {
					ut = getUETableBySelected(me);
					if (ut) {
						me.fireEvent("saveScene");
						for (var i = 0, ci; ci = ut.selectedTds[i++];) {
							domUtils.fillNode(me.document, ci)
						}
						me.fireEvent("saveScene");
						domUtils.preventDefault(evt)
					}
				}
				if (keyCode == 13) {
					var rng = me.selection.getRange(),
						caption = domUtils.findParentByTagName(rng.startContainer, "caption",
							true);
					if (caption) {
						var table = domUtils.findParentByTagName(caption, "table");
						if (!rng.collapsed) {
							rng.deleteContents();
							me.fireEvent("saveScene")
						} else {
							if (caption) {
								rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true)
							}
						}
						domUtils.preventDefault(evt);
						return
					}
					if (rng.collapsed) {
						var table = domUtils.findParentByTagName(rng.startContainer, "table");
						if (table) {
							var cell = table.rows[0].cells[0],
								start = domUtils.findParentByTagName(me.selection.getStart(), [
									"td", "th"
								], true),
								preNode = table.previousSibling;
							if (cell === start && (!preNode || preNode.nodeType == 1 && preNode
									.tagName == "TABLE") && domUtils.isStartInblock(rng)) {
								var first = domUtils.findParent(me.selection.getStart(),
									function(n) {
										return domUtils.isBlockElm(n)
									}, true);
								if (first && (/t(h|d)/i.test(first.tagName) || first === start
										.firstChild)) {
									me.execCommand("insertparagraphbeforetable");
									domUtils.preventDefault(evt)
								}
							}
						}
					}
				}
				if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == "67") {
					tableCopyList = null;
					var ut = getUETableBySelected(me);
					if (ut) {
						var tds = ut.selectedTds;
						isFullCol = ut.isFullCol();
						isFullRow = ut.isFullRow();
						tableCopyList = [
							[ut.cloneCell(tds[0], null, true)]
						];
						for (var i = 1, ci; ci = tds[i]; i++) {
							if (ci.parentNode !== tds[i - 1].parentNode) {
								tableCopyList.push([ut.cloneCell(ci, null, true)])
							} else {
								tableCopyList[tableCopyList.length - 1].push(ut.cloneCell(ci,
									null, true))
							}
						}
					}
				}
			});
			me.addListener("tablehasdeleted", function() {
				toggleDraggableState(this, false, "", null);
				if (dragButton) domUtils.remove(dragButton)
			});
			me.addListener("beforepaste", function(cmd, html) {
				var me = this;
				var rng = me.selection.getRange();
				if (domUtils.findParentByTagName(rng.startContainer, "caption", true)) {
					var div = me.document.createElement("div");
					div.innerHTML = html.html;
					html.html = div[browser.ie9below ? "innerText" : "textContent"];
					return
				}
				var table = getUETableBySelected(me);
				if (tableCopyList) {
					me.fireEvent("saveScene");
					var rng = me.selection.getRange();
					var td = domUtils.findParentByTagName(rng.startContainer, ["td", "th"],
							true),
						tmpNode, preNode;
					if (td) {
						var ut = getUETable(td);
						if (isFullRow) {
							var rowIndex = ut.getCellInfo(td).rowIndex;
							if (td.tagName == "TH") {
								rowIndex++
							}
							for (var i = 0, ci; ci = tableCopyList[i++];) {
								var tr = ut.insertRow(rowIndex++, "td");
								for (var j = 0, cj; cj = ci[j]; j++) {
									var cell = tr.cells[j];
									if (!cell) {
										cell = tr.insertCell(j)
									}
									cell.innerHTML = cj.innerHTML;
									cj.getAttribute("width") && cell.setAttribute("width", cj
										.getAttribute("width"));
									cj.getAttribute("vAlign") && cell.setAttribute("vAlign", cj
										.getAttribute("vAlign"));
									cj.getAttribute("align") && cell.setAttribute("align", cj
										.getAttribute("align"));
									cj.style.cssText && (cell.style.cssText = cj.style.cssText)
								}
								for (var j = 0, cj; cj = tr.cells[j]; j++) {
									if (!ci[j]) break;
									cj.innerHTML = ci[j].innerHTML;
									ci[j].getAttribute("width") && cj.setAttribute("width", ci[
										j].getAttribute("width"));
									ci[j].getAttribute("vAlign") && cj.setAttribute("vAlign",
										ci[j].getAttribute("vAlign"));
									ci[j].getAttribute("align") && cj.setAttribute("align", ci[
										j].getAttribute("align"));
									ci[j].style.cssText && (cj.style.cssText = ci[j].style
										.cssText)
								}
							}
						} else {
							if (isFullCol) {
								cellInfo = ut.getCellInfo(td);
								var maxColNum = 0;
								for (var j = 0, ci = tableCopyList[0], cj; cj = ci[j++];) {
									maxColNum += cj.colSpan || 1
								}
								me.__hasEnterExecCommand = true;
								for (i = 0; i < maxColNum; i++) {
									me.execCommand("insertcol")
								}
								me.__hasEnterExecCommand = false;
								td = ut.table.rows[0].cells[cellInfo.cellIndex];
								if (td.tagName == "TH") {
									td = ut.table.rows[1].cells[cellInfo.cellIndex]
								}
							}
							for (var i = 0, ci; ci = tableCopyList[i++];) {
								tmpNode = td;
								for (var j = 0, cj; cj = ci[j++];) {
									if (td) {
										td.innerHTML = cj.innerHTML;
										cj.getAttribute("width") && td.setAttribute("width", cj
											.getAttribute("width"));
										cj.getAttribute("vAlign") && td.setAttribute("vAlign",
											cj.getAttribute("vAlign"));
										cj.getAttribute("align") && td.setAttribute("align", cj
											.getAttribute("align"));
										cj.style.cssText && (td.style.cssText = cj.style
											.cssText);
										preNode = td;
										td = td.nextSibling
									} else {
										var cloneTd = cj.cloneNode(true);
										domUtils.removeAttributes(cloneTd, ["class", "rowSpan",
											"colSpan"
										]);
										preNode.parentNode.appendChild(cloneTd)
									}
								}
								td = ut.getNextCell(tmpNode, true, true);
								if (!tableCopyList[i]) break;
								if (!td) {
									var cellInfo = ut.getCellInfo(tmpNode);
									ut.table.insertRow(ut.table.rows.length);
									ut.update();
									td = ut.getVSideCell(tmpNode, true)
								}
							}
						}
						ut.update()
					} else {
						table = me.document.createElement("table");
						for (var i = 0, ci; ci = tableCopyList[i++];) {
							var tr = table.insertRow(table.rows.length);
							for (var j = 0, cj; cj = ci[j++];) {
								cloneTd = UT.cloneCell(cj, null, true);
								domUtils.removeAttributes(cloneTd, ["class"]);
								tr.appendChild(cloneTd)
							}
							if (j == 2 && cloneTd.rowSpan > 1) {
								cloneTd.rowSpan = 1
							}
						}
						var defaultValue = getDefaultValue(me),
							width = me.body.offsetWidth - (needIEHack ? parseInt(domUtils
								.getComputedStyle(me.body, "margin-left"), 10) * 2 : 0) -
							defaultValue.tableBorder * 2 - (me.options.offsetWidth || 0);
						me.execCommand("insertHTML", "<table  " + (isFullCol && isFullRow ?
								'width="' + width + '"' : "") + ">" + table.innerHTML
							.replace(/>\s*</g, "><").replace(/\bth\b/gi, "td") + "</table>")
					}
					me.fireEvent("contentchange");
					me.fireEvent("saveScene");
					html.html = "";
					return true
				} else {
					var div = me.document.createElement("div"),
						tables;
					div.innerHTML = html.html;
					tables = div.getElementsByTagName("table");
					if (domUtils.findParentByTagName(me.selection.getStart(), "table")) {
						utils.each(tables, function(t) {
							domUtils.remove(t)
						});
						if (domUtils.findParentByTagName(me.selection.getStart(), "caption",
								true)) {
							div.innerHTML = div[browser.ie ? "innerText" : "textContent"]
						}
					} else {
						utils.each(tables, function(table) {
							removeStyleSize(table, true);
							domUtils.removeAttributes(table, ["style", "border"]);
							utils.each(domUtils.getElementsByTagName(table, "td"),
								function(td) {
									if (isEmptyBlock(td)) {
										domUtils.fillNode(me.document, td)
									}
									removeStyleSize(td, true)
								})
						})
					}
					html.html = div.innerHTML
				}
			});
			me.addListener("afterpaste", function() {
				utils.each(domUtils.getElementsByTagName(me.body, "table"), function(table) {
					if (table.offsetWidth > me.body.offsetWidth) {
						var defaultValue = getDefaultValue(me, table);
						table.style.width = me.body.offsetWidth - (needIEHack ?
								parseInt(domUtils.getComputedStyle(me.body,
									"margin-left"), 10) * 2 : 0) - defaultValue
							.tableBorder * 2 - (me.options.offsetWidth || 0) + "px"
					}
				})
			});
			me.addListener("blur", function() {
				tableCopyList = null
			});
			var timer;
			me.addListener("keydown", function() {
				clearTimeout(timer);
				timer = setTimeout(function() {
					var rng = me.selection.getRange(),
						cell = domUtils.findParentByTagName(rng.startContainer, ["th",
							"td"
						], true);
					if (cell) {
						var table = cell.parentNode.parentNode.parentNode;
						if (table.offsetWidth > table.getAttribute("width")) {
							cell.style.wordBreak = "break-all"
						}
					}
				}, 100)
			});
			me.addListener("selectionchange", function() {
				toggleDraggableState(me, false, "", null)
			});
			me.addListener("contentchange", function() {
				var me = this;
				hideDragLine(me);
				if (getUETableBySelected(me)) return;
				var rng = me.selection.getRange();
				var start = rng.startContainer;
				start = domUtils.findParentByTagName(start, ["td", "th"], true);
				utils.each(domUtils.getElementsByTagName(me.document, "table"), function(
				table) {
					if (me.fireEvent("excludetable", table) === true) return;
					table.ueTable = new UT(table);
					table.onmouseover = function() {
						me.fireEvent("tablemouseover", table)
					};
					table.onmousemove = function() {
						me.fireEvent("tablemousemove", table);
						me.options.tableDragable && toggleDragButton(true, this,
						me);
						utils.defer(function() {
							me.fireEvent("contentchange", 50)
						}, true)
					};
					table.onmouseout = function() {
						me.fireEvent("tablemouseout", table);
						toggleDraggableState(me, false, "", null);
						hideDragLine(me)
					};
					table.onclick = function(evt) {
						evt = me.window.event || evt;
						var target = getParentTdOrTh(evt.target || evt.srcElement);
						if (!target) return;
						var ut = getUETable(target),
							table = ut.table,
							cellInfo = ut.getCellInfo(target),
							cellsRange, rng = me.selection.getRange();
						if (inTableSide(table, target, evt, true)) {
							var endTdCol = ut.getCell(ut.indexTable[ut.rowsNum - 1][
								cellInfo.colIndex
							].rowIndex, ut.indexTable[ut.rowsNum - 1][
								cellInfo.colIndex
							].cellIndex);
							if (evt.shiftKey && ut.selectedTds.length) {
								if (ut.selectedTds[0] !== endTdCol) {
									cellsRange = ut.getCellsRange(ut.selectedTds[0],
										endTdCol);
									ut.setSelected(cellsRange)
								} else {
									rng && rng.selectNodeContents(endTdCol).select()
								}
							} else {
								if (target !== endTdCol) {
									cellsRange = ut.getCellsRange(target, endTdCol);
									ut.setSelected(cellsRange)
								} else {
									rng && rng.selectNodeContents(endTdCol).select()
								}
							}
							return
						}
						if (inTableSide(table, target, evt)) {
							var endTdRow = ut.getCell(ut.indexTable[cellInfo
									.rowIndex][ut.colsNum - 1].rowIndex, ut
								.indexTable[cellInfo.rowIndex][ut.colsNum - 1]
								.cellIndex);
							if (evt.shiftKey && ut.selectedTds.length) {
								if (ut.selectedTds[0] !== endTdRow) {
									cellsRange = ut.getCellsRange(ut.selectedTds[0],
										endTdRow);
									ut.setSelected(cellsRange)
								} else {
									rng && rng.selectNodeContents(endTdRow).select()
								}
							} else {
								if (target !== endTdRow) {
									cellsRange = ut.getCellsRange(target, endTdRow);
									ut.setSelected(cellsRange)
								} else {
									rng && rng.selectNodeContents(endTdRow).select()
								}
							}
						}
					}
				});
				switchBorderColor(me, true)
			});
			domUtils.on(me.document, "mousemove", mouseMoveEvent);
			domUtils.on(me.document, "mouseout", function(evt) {
				var target = evt.target || evt.srcElement;
				if (target.tagName == "TABLE") {
					toggleDraggableState(me, false, "", null)
				}
			});
			me.addListener("interlacetable", function(type, table, classList) {
				if (!table) return;
				var me = this,
					rows = table.rows,
					len = rows.length,
					getClass = function(list, index, repeat) {
						return list[index] ? list[index] : repeat ? list[index % list.length] :
							""
					};
				for (var i = 0; i < len; i++) {
					rows[i].className = getClass(classList || me.options.classList, i, true)
				}
			});
			me.addListener("uninterlacetable", function(type, table) {
				if (!table) return;
				var me = this,
					rows = table.rows,
					classList = me.options.classList,
					len = rows.length;
				for (var i = 0; i < len; i++) {
					domUtils.removeClasses(rows[i], classList)
				}
			});
			me.addListener("mousedown", mouseDownEvent);
			me.addListener("mouseup", mouseUpEvent);
			domUtils.on(me.body, "dragstart", function(evt) {
				mouseUpEvent.call(me, "dragstart", evt)
			});
			me.addOutputRule(function(root) {
				utils.each(root.getNodesByTagName("div"), function(n) {
					if (n.getAttr("id") == "ue_tableDragLine") {
						n.parentNode.removeChild(n)
					}
				})
			});
			var currentRowIndex = 0;
			me.addListener("mousedown", function() {
				currentRowIndex = 0
			});
			me.addListener("tabkeydown", function() {
				var range = this.selection.getRange(),
					common = range.getCommonAncestor(true, true),
					table = domUtils.findParentByTagName(common, "table");
				if (table) {
					if (domUtils.findParentByTagName(common, "caption", true)) {
						var cell = domUtils.getElementsByTagName(table, "th td");
						if (cell && cell.length) {
							range.setStart(cell[0], 0).setCursor(false, true)
						}
					} else {
						var cell = domUtils.findParentByTagName(common, ["td", "th"], true),
							ua = getUETable(cell);
						currentRowIndex = cell.rowSpan > 1 ? currentRowIndex : ua.getCellInfo(
							cell).rowIndex;
						var nextCell = ua.getTabNextCell(cell, currentRowIndex);
						if (nextCell) {
							if (isEmptyBlock(nextCell)) {
								range.setStart(nextCell, 0).setCursor(false, true)
							} else {
								range.selectNodeContents(nextCell).select()
							}
						} else {
							me.fireEvent("saveScene");
							me.__hasEnterExecCommand = true;
							this.execCommand("insertrownext");
							me.__hasEnterExecCommand = false;
							range = this.selection.getRange();
							range.setStart(table.rows[table.rows.length - 1].cells[0], 0)
								.setCursor();
							me.fireEvent("saveScene")
						}
					}
					return true
				}
			});
			browser.ie && me.addListener("selectionchange", function() {
				toggleDraggableState(this, false, "", null)
			});
			me.addListener("keydown", function(type, evt) {
				var me = this;
				var keyCode = evt.keyCode || evt.which;
				if (keyCode == 8 || keyCode == 46) {
					return
				}
				var notCtrlKey = !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey;
				notCtrlKey && removeSelectedClass(domUtils.getElementsByTagName(me.body, "td"));
				var ut = getUETableBySelected(me);
				if (!ut) return;
				notCtrlKey && ut.clearSelected()
			});
			me.addListener("beforegetcontent", function() {
				switchBorderColor(this, false);
				browser.ie && utils.each(this.document.getElementsByTagName("caption"),
					function(ci) {
						if (domUtils.isEmptyNode(ci)) {
							ci.innerHTML = "&nbsp;"
						}
					})
			});
			me.addListener("aftergetcontent", function() {
				switchBorderColor(this, true)
			});
			me.addListener("getAllHtml", function() {
				removeSelectedClass(me.document.getElementsByTagName("td"))
			});
			me.addListener("fullscreenchanged", function(type, fullscreen) {
				if (!fullscreen) {
					var ratio = this.body.offsetWidth / document.body.offsetWidth,
						tables = domUtils.getElementsByTagName(this.body, "table");
					utils.each(tables, function(table) {
						if (table.offsetWidth < me.body.offsetWidth) return false;
						var tds = domUtils.getElementsByTagName(table, "td"),
							backWidths = [];
						utils.each(tds, function(td) {
							backWidths.push(td.offsetWidth)
						});
						for (var i = 0, td; td = tds[i]; i++) {
							td.setAttribute("width", Math.floor(backWidths[i] * ratio))
						}
						table.setAttribute("width", Math.floor(getTableWidth(me,
							needIEHack, getDefaultValue(me))))
					})
				}
			});
			var oldExecCommand = me.execCommand;
			me.execCommand = function(cmd, datatat) {
				var me = this,
					args = arguments;
				cmd = cmd.toLowerCase();
				var ut = getUETableBySelected(me),
					tds, range = new dom.Range(me.document),
					cmdFun = me.commands[cmd] || UE.commands[cmd],
					result;
				if (!cmdFun) return;
				if (ut && !commands[cmd] && !cmdFun.notNeedUndo && !me.__hasEnterExecCommand) {
					me.__hasEnterExecCommand = true;
					me.fireEvent("beforeexeccommand", cmd);
					tds = ut.selectedTds;
					var lastState = -2,
						lastValue = -2,
						value, state;
					for (var i = 0, td; td = tds[i]; i++) {
						if (isEmptyBlock(td)) {
							range.setStart(td, 0).setCursor(false, true)
						} else {
							range.selectNode(td).select(true)
						}
						state = me.queryCommandState(cmd);
						value = me.queryCommandValue(cmd);
						if (state != -1) {
							if (lastState !== state || lastValue !== value) {
								me._ignoreContentChange = true;
								result = oldExecCommand.apply(me, arguments);
								me._ignoreContentChange = false
							}
							lastState = me.queryCommandState(cmd);
							lastValue = me.queryCommandValue(cmd);
							if (domUtils.isEmptyBlock(td)) {
								domUtils.fillNode(me.document, td)
							}
						}
					}
					range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true);
					me.fireEvent("contentchange");
					me.fireEvent("afterexeccommand", cmd);
					me.__hasEnterExecCommand = false;
					me._selectionChange()
				} else {
					result = oldExecCommand.apply(me, arguments)
				}
				return result
			}
		});

		function removeStyleSize(obj, replaceToProperty) {
			removeStyle(obj, "width", true);
			removeStyle(obj, "height", true)
		}

		function removeStyle(obj, styleName, replaceToProperty) {
			if (obj.style[styleName]) {
				replaceToProperty && obj.setAttribute(styleName, parseInt(obj.style[styleName], 10));
				obj.style[styleName] = ""
			}
		}

		function getParentTdOrTh(ele) {
			if (ele.tagName == "TD" || ele.tagName == "TH") return ele;
			var td;
			if (td = domUtils.findParentByTagName(ele, "td", true) || domUtils.findParentByTagName(ele, "th",
					true)) return td;
			return null
		}

		function isEmptyBlock(node) {
			var reg = new RegExp(domUtils.fillChar, "g");
			if (node[browser.ie ? "innerText" : "textContent"].replace(/^\s*$/, "").replace(reg, "").length >
				0) {
				return 0
			}
			for (var n in dtd.$isNotEmpty) {
				if (node.getElementsByTagName(n).length) {
					return 0
				}
			}
			return 1
		}

		function mouseCoords(evt) {
			if (evt.pageX || evt.pageY) {
				return {
					x: evt.pageX,
					y: evt.pageY
				}
			}
			return {
				x: evt.clientX + me.document.body.scrollLeft - me.document.body.clientLeft,
				y: evt.clientY + me.document.body.scrollTop - me.document.body.clientTop
			}
		}

		function mouseMoveEvent(evt) {
			if (isEditorDisabled()) {
				return
			}
			try {
				var target = getParentTdOrTh(evt.target || evt.srcElement),
					pos;
				if (isInResizeBuffer) {
					me.body.style.webkitUserSelect = "none";
					if (Math.abs(userActionStatus.x - evt.clientX) > offsetOfTableCell || Math.abs(
							userActionStatus.y - evt.clientY) > offsetOfTableCell) {
						clearTableDragTimer();
						isInResizeBuffer = false;
						singleClickState = 0;
						tableBorderDrag(evt)
					}
				}
				if (onDrag && dragTd) {
					singleClickState = 0;
					me.body.style.webkitUserSelect = "none";
					me.selection.getNative()[browser.ie9below ? "empty" : "removeAllRanges"]();
					pos = mouseCoords(evt);
					toggleDraggableState(me, true, onDrag, pos, target);
					if (onDrag == "h") {
						dragLine.style.left = getPermissionX(dragTd, evt) + "px"
					} else if (onDrag == "v") {
						dragLine.style.top = getPermissionY(dragTd, evt) + "px"
					}
					return
				}
				if (target) {
					if (me.fireEvent("excludetable", target) === true) return;
					pos = mouseCoords(evt);
					var state = getRelation(target, pos),
						table = domUtils.findParentByTagName(target, "table", true);
					if (inTableSide(table, target, evt, true)) {
						if (me.fireEvent("excludetable", table) === true) return;
						me.body.style.cursor = "url(" + me.options.cursorpath + "h.png),pointer"
					} else if (inTableSide(table, target, evt)) {
						if (me.fireEvent("excludetable", table) === true) return;
						me.body.style.cursor = "url(" + me.options.cursorpath + "v.png),pointer"
					} else {
						me.body.style.cursor = "text";
						var curCell = target;
						if (/\d/.test(state)) {
							state = state.replace(/\d/, "");
							target = getUETable(target).getPreviewCell(target, state == "v")
						}
						toggleDraggableState(me, target ? !!state : false, target ? state : "", pos, target)
					}
				} else {
					toggleDragButton(false, table, me)
				}
			} catch (e) {
				showError(e)
			}
		}
		var dragButtonTimer;

		function toggleDragButton(show, table, editor) {
			if (!show) {
				if (dragOver) return;
				dragButtonTimer = setTimeout(function() {
					!dragOver && dragButton && dragButton.parentNode && dragButton.parentNode
						.removeChild(dragButton)
				}, 2e3)
			} else {
				createDragButton(table, editor)
			}
		}

		function createDragButton(table, editor) {
			var pos = domUtils.getXY(table),
				doc = table.ownerDocument;
			if (dragButton && dragButton.parentNode) return dragButton;
			dragButton = doc.createElement("div");
			dragButton.contentEditable = false;
			dragButton.innerHTML = "";
			dragButton.style.cssText = "width:15px;height:15px;background-image:url(" + editor.options
				.UEDITOR_HOME_URL + "dialogs/table/dragicon.png);position: absolute;cursor:move;top:" + (pos.y -
					15) + "px;left:" + pos.x + "px;";
			domUtils.unSelectable(dragButton);
			dragButton.onmouseover = function(evt) {
				dragOver = true
			};
			dragButton.onmouseout = function(evt) {
				dragOver = false
			};
			domUtils.on(dragButton, "click", function(type, evt) {
				doClick(evt, this)
			});
			domUtils.on(dragButton, "dblclick", function(type, evt) {
				doDblClick(evt)
			});
			domUtils.on(dragButton, "dragstart", function(type, evt) {
				domUtils.preventDefault(evt)
			});
			var timer;

			function doClick(evt, button) {
				clearTimeout(timer);
				timer = setTimeout(function() {
					editor.fireEvent("tableClicked", table, button)
				}, 300)
			}

			function doDblClick(evt) {
				clearTimeout(timer);
				var ut = getUETable(table),
					start = table.rows[0].cells[0],
					end = ut.getLastCell(),
					range = ut.getCellsRange(start, end);
				editor.selection.getRange().setStart(start, 0).setCursor(false, true);
				ut.setSelected(range)
			}
			doc.body.appendChild(dragButton)
		}

		function inTableSide(table, cell, evt, top) {
			var pos = mouseCoords(evt),
				state = getRelation(cell, pos);
			if (top) {
				var caption = table.getElementsByTagName("caption")[0],
					capHeight = caption ? caption.offsetHeight : 0;
				return state == "v1" && pos.y - domUtils.getXY(table).y - capHeight < 8
			} else {
				return state == "h1" && pos.x - domUtils.getXY(table).x < 8
			}
		}

		function getPermissionX(dragTd, evt) {
			var ut = getUETable(dragTd);
			if (ut) {
				var preTd = ut.getSameEndPosCells(dragTd, "x")[0],
					nextTd = ut.getSameStartPosXCells(dragTd)[0],
					mouseX = mouseCoords(evt).x,
					left = (preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20,
					right = nextTd ? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20 : me.body.offsetWidth +
					5 || parseInt(domUtils.getComputedStyle(me.body, "width"), 10);
				left += cellMinWidth;
				right -= cellMinWidth;
				return mouseX < left ? left : mouseX > right ? right : mouseX
			}
		}

		function getPermissionY(dragTd, evt) {
			try {
				var top = domUtils.getXY(dragTd).y,
					mousePosY = mouseCoords(evt).y;
				return mousePosY < top ? top : mousePosY
			} catch (e) {
				showError(e)
			}
		}

		function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
			try {
				editor.body.style.cursor = dir == "h" ? "col-resize" : dir == "v" ? "row-resize" : "text";
				if (browser.ie) {
					if (dir && !mousedown && !getUETableBySelected(editor)) {
						getDragLine(editor, editor.document);
						showDragLineAt(dir, cell)
					} else {
						hideDragLine(editor)
					}
				}
				onBorder = draggable
			} catch (e) {
				showError(e)
			}
		}

		function getResizeLineByUETable() {
			var lineId = "_UETableResizeLine",
				line = this.document.getElementById(lineId);
			if (!line) {
				line = this.document.createElement("div");
				line.id = lineId;
				line.contnetEditable = false;
				line.setAttribute("unselectable", "on");
				var styles = {
					width: 2 * cellBorderWidth + 1 + "px",
					position: "absolute",
					"z-index": 1e5,
					cursor: "col-resize",
					background: "red",
					display: "none"
				};
				line.onmouseout = function() {
					this.style.display = "none"
				};
				utils.extend(line.style, styles);
				this.document.body.appendChild(line)
			}
			return line
		}

		function updateResizeLine(cell, uetable) {
			var line = getResizeLineByUETable.call(this),
				table = uetable.table,
				styles = {
					top: domUtils.getXY(table).y + "px",
					left: domUtils.getXY(cell).x + cell.offsetWidth - cellBorderWidth + "px",
					display: "block",
					height: table.offsetHeight + "px"
				};
			utils.extend(line.style, styles)
		}

		function showResizeLine(cell) {
			var uetable = getUETable(cell);
			updateResizeLine.call(this, cell, uetable)
		}

		function getRelation(ele, mousePos) {
			var elePos = domUtils.getXY(ele);
			if (!elePos) {
				return ""
			}
			if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
				return "h"
			}
			if (mousePos.x - elePos.x < cellBorderWidth) {
				return "h1"
			}
			if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
				return "v"
			}
			if (mousePos.y - elePos.y < cellBorderWidth) {
				return "v1"
			}
			return ""
		}

		function mouseDownEvent(type, evt) {
			if (isEditorDisabled()) {
				return
			}
			userActionStatus = {
				x: evt.clientX,
				y: evt.clientY
			};
			if (evt.button == 2) {
				var ut = getUETableBySelected(me),
					flag = false;
				if (ut) {
					var td = getTargetTd(me, evt);
					utils.each(ut.selectedTds, function(ti) {
						if (ti === td) {
							flag = true
						}
					});
					if (!flag) {
						removeSelectedClass(domUtils.getElementsByTagName(me.body, "th td"));
						ut.clearSelected()
					} else {
						td = ut.selectedTds[0];
						setTimeout(function() {
							me.selection.getRange().setStart(td, 0).setCursor(false, true)
						}, 0)
					}
				}
			} else {
				tableClickHander(evt)
			}
		}

		function clearTableTimer() {
			tabTimer && clearTimeout(tabTimer);
			tabTimer = null
		}

		function tableDbclickHandler(evt) {
			singleClickState = 0;
			evt = evt || me.window.event;
			var target = getParentTdOrTh(evt.target || evt.srcElement);
			if (target) {
				var h;
				if (h = getRelation(target, mouseCoords(evt))) {
					hideDragLine(me);
					if (h == "h1") {
						h = "h";
						if (inTableSide(domUtils.findParentByTagName(target, "table"), target, evt)) {
							me.execCommand("adaptbywindow")
						} else {
							target = getUETable(target).getPreviewCell(target);
							if (target) {
								var rng = me.selection.getRange();
								rng.selectNodeContents(target).setCursor(true, true)
							}
						}
					}
					if (h == "h") {
						var ut = getUETable(target),
							table = ut.table,
							cells = getCellsByMoveBorder(target, table, true);
						cells = extractArray(cells, "left");
						ut.width = ut.offsetWidth;
						var oldWidth = [],
							newWidth = [];
						utils.each(cells, function(cell) {
							oldWidth.push(cell.offsetWidth)
						});
						utils.each(cells, function(cell) {
							cell.removeAttribute("width")
						});
						window.setTimeout(function() {
							var changeable = true;
							utils.each(cells, function(cell, index) {
								var width = cell.offsetWidth;
								if (width > oldWidth[index]) {
									changeable = false;
									return false
								}
								newWidth.push(width)
							});
							var change = changeable ? newWidth : oldWidth;
							utils.each(cells, function(cell, index) {
								cell.width = change[index] - getTabcellSpace()
							})
						}, 0)
					}
				}
			}
		}

		function tableClickHander(evt) {
			removeSelectedClass(domUtils.getElementsByTagName(me.body, "td th"));
			utils.each(me.document.getElementsByTagName("table"), function(t) {
				t.ueTable = null
			});
			startTd = getTargetTd(me, evt);
			if (!startTd) return;
			var table = domUtils.findParentByTagName(startTd, "table", true);
			ut = getUETable(table);
			ut && ut.clearSelected();
			if (!onBorder) {
				me.document.body.style.webkitUserSelect = "";
				mousedown = true;
				me.addListener("mouseover", mouseOverEvent)
			} else {
				borderActionHandler(evt)
			}
		}

		function borderActionHandler(evt) {
			if (browser.ie) {
				evt = reconstruct(evt)
			}
			clearTableDragTimer();
			isInResizeBuffer = true;
			tableDragTimer = setTimeout(function() {
				tableBorderDrag(evt)
			}, dblclickTime)
		}

		function extractArray(originArr, key) {
			var result = [],
				tmp = null;
			for (var i = 0, len = originArr.length; i < len; i++) {
				tmp = originArr[i][key];
				if (tmp) {
					result.push(tmp)
				}
			}
			return result
		}

		function clearTableDragTimer() {
			tableDragTimer && clearTimeout(tableDragTimer);
			tableDragTimer = null
		}

		function reconstruct(obj) {
			var attrs = ["pageX", "pageY", "clientX", "clientY", "srcElement", "target"],
				newObj = {};
			if (obj) {
				for (var i = 0, key, val; key = attrs[i]; i++) {
					val = obj[key];
					val && (newObj[key] = val)
				}
			}
			return newObj
		}

		function tableBorderDrag(evt) {
			isInResizeBuffer = false;
			startTd = evt.target || evt.srcElement;
			if (!startTd) return;
			var state = getRelation(startTd, mouseCoords(evt));
			if (/\d/.test(state)) {
				state = state.replace(/\d/, "");
				startTd = getUETable(startTd).getPreviewCell(startTd, state == "v")
			}
			hideDragLine(me);
			getDragLine(me, me.document);
			me.fireEvent("saveScene");
			showDragLineAt(state, startTd);
			mousedown = true;
			onDrag = state;
			dragTd = startTd
		}

		function mouseUpEvent(type, evt) {
			if (isEditorDisabled()) {
				return
			}
			clearTableDragTimer();
			isInResizeBuffer = false;
			if (onBorder) {
				singleClickState = ++singleClickState % 3;
				userActionStatus = {
					x: evt.clientX,
					y: evt.clientY
				};
				tableResizeTimer = setTimeout(function() {
					singleClickState > 0 && singleClickState--
				}, dblclickTime);
				if (singleClickState === 2) {
					singleClickState = 0;
					tableDbclickHandler(evt);
					return
				}
			}
			if (evt.button == 2) return;
			var me = this;
			var range = me.selection.getRange(),
				start = domUtils.findParentByTagName(range.startContainer, "table", true),
				end = domUtils.findParentByTagName(range.endContainer, "table", true);
			if (start || end) {
				if (start === end) {
					start = domUtils.findParentByTagName(range.startContainer, ["td", "th", "caption"], true);
					end = domUtils.findParentByTagName(range.endContainer, ["td", "th", "caption"], true);
					if (start !== end) {
						me.selection.clearRange()
					}
				} else {
					me.selection.clearRange()
				}
			}
			mousedown = false;
			me.document.body.style.webkitUserSelect = "";
			if (onDrag && dragTd) {
				me.selection.getNative()[browser.ie9below ? "empty" : "removeAllRanges"]();
				singleClickState = 0;
				dragLine = me.document.getElementById("ue_tableDragLine");
				if (dragLine) {
					var dragTdPos = domUtils.getXY(dragTd),
						dragLinePos = domUtils.getXY(dragLine);
					switch (onDrag) {
						case "h":
							changeColWidth(dragTd, dragLinePos.x - dragTdPos.x);
							break;
						case "v":
							changeRowHeight(dragTd, dragLinePos.y - dragTdPos.y - dragTd.offsetHeight);
							break;
						default:
					}
					onDrag = "";
					dragTd = null;
					hideDragLine(me);
					me.fireEvent("saveScene");
					return
				}
			}
			if (!startTd) {
				var target = domUtils.findParentByTagName(evt.target || evt.srcElement, "td", true);
				if (!target) target = domUtils.findParentByTagName(evt.target || evt.srcElement, "th", true);
				if (target && (target.tagName == "TD" || target.tagName == "TH")) {
					if (me.fireEvent("excludetable", target) === true) return;
					range = new dom.Range(me.document);
					range.setStart(target, 0).setCursor(false, true)
				}
			} else {
				var ut = getUETable(startTd),
					cell = ut ? ut.selectedTds[0] : null;
				if (cell) {
					range = new dom.Range(me.document);
					if (domUtils.isEmptyBlock(cell)) {
						range.setStart(cell, 0).setCursor(false, true)
					} else {
						range.selectNodeContents(cell).shrinkBoundary().setCursor(false, true)
					}
				} else {
					range = me.selection.getRange().shrinkBoundary();
					if (!range.collapsed) {
						var start = domUtils.findParentByTagName(range.startContainer, ["td", "th"], true),
							end = domUtils.findParentByTagName(range.endContainer, ["td", "th"], true);
						if (start && !end || !start && end || start && end && start !== end) {
							range.setCursor(false, true)
						}
					}
				}
				startTd = null;
				me.removeListener("mouseover", mouseOverEvent)
			}
			me._selectionChange(250, evt)
		}

		function mouseOverEvent(type, evt) {
			if (isEditorDisabled()) {
				return
			}
			var me = this,
				tar = evt.target || evt.srcElement;
			currentTd = domUtils.findParentByTagName(tar, "td", true) || domUtils.findParentByTagName(tar, "th",
				true);
			if (startTd && currentTd && (startTd.tagName == "TD" && currentTd.tagName == "TD" || startTd
					.tagName == "TH" && currentTd.tagName == "TH") && domUtils.findParentByTagName(startTd,
					"table") == domUtils.findParentByTagName(currentTd, "table")) {
				var ut = getUETable(currentTd);
				if (startTd != currentTd) {
					me.document.body.style.webkitUserSelect = "none";
					me.selection.getNative()[browser.ie9below ? "empty" : "removeAllRanges"]();
					var range = ut.getCellsRange(startTd, currentTd);
					ut.setSelected(range)
				} else {
					me.document.body.style.webkitUserSelect = "";
					ut.clearSelected()
				}
			}
			evt.preventDefault ? evt.preventDefault() : evt.returnValue = false
		}

		function setCellHeight(cell, height, backHeight) {
			var lineHight = parseInt(domUtils.getComputedStyle(cell, "line-height"), 10),
				tmpHeight = backHeight + height;
			height = tmpHeight < lineHight ? lineHight : tmpHeight;
			if (cell.style.height) cell.style.height = "";
			cell.rowSpan == 1 ? cell.setAttribute("height", height) : cell.removeAttribute && cell
				.removeAttribute("height")
		}

		function getWidth(cell) {
			if (!cell) return 0;
			return parseInt(domUtils.getComputedStyle(cell, "width"), 10)
		}

		function changeColWidth(cell, changeValue) {
			var ut = getUETable(cell);
			if (ut) {
				var table = ut.table,
					cells = getCellsByMoveBorder(cell, table);
				table.style.width = "";
				table.removeAttribute("width");
				changeValue = correctChangeValue(changeValue, cell, cells);
				if (cell.nextSibling) {
					var i = 0;
					utils.each(cells, function(cellGroup) {
						cellGroup.left.width = +cellGroup.left.width + changeValue;
						cellGroup.right && (cellGroup.right.width = +cellGroup.right.width -
							changeValue)
					})
				} else {
					utils.each(cells, function(cellGroup) {
						cellGroup.left.width -= -changeValue
					})
				}
			}
		}

		function isEditorDisabled() {
			return me.body.contentEditable === "false"
		}

		function changeRowHeight(td, changeValue) {
			if (Math.abs(changeValue) < 10) return;
			var ut = getUETable(td);
			if (ut) {
				var cells = ut.getSameEndPosCells(td, "y"),
					backHeight = cells[0] ? cells[0].offsetHeight : 0;
				for (var i = 0, cell; cell = cells[i++];) {
					setCellHeight(cell, changeValue, backHeight)
				}
			}
		}

		function getCellsByMoveBorder(cell, table, isContainMergeCell) {
			if (!table) {
				table = domUtils.findParentByTagName(cell, "table")
			}
			if (!table) {
				return null
			}
			var index = domUtils.getNodeIndex(cell),
				temp = cell,
				rows = table.rows,
				colIndex = 0;
			while (temp) {
				if (temp.nodeType === 1) {
					colIndex += temp.colSpan || 1
				}
				temp = temp.previousSibling
			}
			temp = null;
			var borderCells = [];
			utils.each(rows, function(tabRow) {
				var cells = tabRow.cells,
					currIndex = 0;
				utils.each(cells, function(tabCell) {
					currIndex += tabCell.colSpan || 1;
					if (currIndex === colIndex) {
						borderCells.push({
							left: tabCell,
							right: tabCell.nextSibling || null
						});
						return false
					} else if (currIndex > colIndex) {
						if (isContainMergeCell) {
							borderCells.push({
								left: tabCell
							})
						}
						return false
					}
				})
			});
			return borderCells
		}

		function getMinWidthByTableCells(cells) {
			var minWidth = Number.MAX_VALUE;
			for (var i = 0, curCell; curCell = cells[i]; i++) {
				minWidth = Math.min(minWidth, curCell.width || getTableCellWidth(curCell))
			}
			return minWidth
		}

		function correctChangeValue(changeValue, relatedCell, cells) {
			changeValue -= getTabcellSpace();
			if (changeValue < 0) {
				return 0
			}
			changeValue -= getTableCellWidth(relatedCell);
			var direction = changeValue < 0 ? "left" : "right";
			changeValue = Math.abs(changeValue);
			utils.each(cells, function(cellGroup) {
				var curCell = cellGroup[direction];
				if (curCell) {
					changeValue = Math.min(changeValue, getTableCellWidth(curCell) - cellMinWidth)
				}
			});
			changeValue = changeValue < 0 ? 0 : changeValue;
			return direction === "left" ? -changeValue : changeValue
		}

		function getTableCellWidth(cell) {
			var width = 0,
				offset = 0,
				width = cell.offsetWidth - getTabcellSpace();
			if (!cell.nextSibling) {
				width -= getTableCellOffset(cell)
			}
			width = width < 0 ? 0 : width;
			try {
				cell.width = width
			} catch (e) {}
			return width
		}

		function getTableCellOffset(cell) {
			tab = domUtils.findParentByTagName(cell, "table", false);
			if (tab.offsetVal === undefined) {
				var prev = cell.previousSibling;
				if (prev) {
					tab.offsetVal = cell.offsetWidth - prev.offsetWidth === UT.borderWidth ? UT.borderWidth : 0
				} else {
					tab.offsetVal = 0
				}
			}
			return tab.offsetVal
		}

		function getTabcellSpace() {
			if (UT.tabcellSpace === undefined) {
				var cell = null,
					tab = me.document.createElement("table"),
					tbody = me.document.createElement("tbody"),
					trow = me.document.createElement("tr"),
					tabcell = me.document.createElement("td"),
					mirror = null;
				tabcell.style.cssText = "border: 0;";
				tabcell.width = 1;
				trow.appendChild(tabcell);
				trow.appendChild(mirror = tabcell.cloneNode(false));
				tbody.appendChild(trow);
				tab.appendChild(tbody);
				tab.style.cssText = "visibility: hidden;";
				me.body.appendChild(tab);
				UT.paddingSpace = tabcell.offsetWidth - 1;
				var tmpTabWidth = tab.offsetWidth;
				tabcell.style.cssText = "";
				mirror.style.cssText = "";
				UT.borderWidth = (tab.offsetWidth - tmpTabWidth) / 3;
				UT.tabcellSpace = UT.paddingSpace + UT.borderWidth;
				me.body.removeChild(tab)
			}
			getTabcellSpace = function() {
				return UT.tabcellSpace
			};
			return UT.tabcellSpace
		}

		function getDragLine(editor, doc) {
			if (mousedown) return;
			dragLine = editor.document.createElement("div");
			domUtils.setAttributes(dragLine, {
				id: "ue_tableDragLine",
				unselectable: "on",
				contenteditable: false,
				onresizestart: "return false",
				ondragstart: "return false",
				onselectstart: "return false",
				style: "background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)"
			});
			editor.body.appendChild(dragLine)
		}

		function hideDragLine(editor) {
			if (mousedown) return;
			var line;
			while (line = editor.document.getElementById("ue_tableDragLine")) {
				domUtils.remove(line)
			}
		}

		function showDragLineAt(state, cell) {
			if (!cell) return;
			var table = domUtils.findParentByTagName(cell, "table"),
				caption = table.getElementsByTagName("caption"),
				width = table.offsetWidth,
				height = table.offsetHeight - (caption.length > 0 ? caption[0].offsetHeight : 0),
				tablePos = domUtils.getXY(table),
				cellPos = domUtils.getXY(cell),
				css;
			switch (state) {
				case "h":
					css = "height:" + height + "px;top:" + (tablePos.y + (caption.length > 0 ? caption[0]
						.offsetHeight : 0)) + "px;left:" + (cellPos.x + cell.offsetWidth);
					dragLine.style.cssText = css +
						"px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)";
					break;
				case "v":
					css = "width:" + width + "px;left:" + tablePos.x + "px;top:" + (cellPos.y + cell
						.offsetHeight);
					dragLine.style.cssText = css +
						"px;overflow:hidden;position: absolute;display:block;background-color:blue;height:1px;border:0;color:blue;opacity:.2;filter:alpha(opacity=20)";
					break;
				default:
			}
		}

		function switchBorderColor(editor, flag) {
			var tableArr = domUtils.getElementsByTagName(editor.body, "table"),
				color;
			for (var i = 0, node; node = tableArr[i++];) {
				var td = domUtils.getElementsByTagName(node, "td");
				if (td[0]) {
					if (flag) {
						color = td[0].style.borderColor.replace(/\s/g, "");
						if (/(#ffffff)|(rgb\(255,255,255\))/gi.test(color)) domUtils.addClass(node,
							"noBorderTable")
					} else {
						domUtils.removeClasses(node, "noBorderTable")
					}
				}
			}
		}

		function getTableWidth(editor, needIEHack, defaultValue) {
			var body = editor.body;
			return body.offsetWidth - (needIEHack ? parseInt(domUtils.getComputedStyle(body, "margin-left"),
				10) * 2 : 0) - defaultValue.tableBorder * 2 - (editor.options.offsetWidth || 0)
		}

		function getTargetTd(editor, evt) {
			var target = domUtils.findParentByTagName(evt.target || evt.srcElement, ["td", "th"], true),
				dir = null;
			if (!target) {
				return null
			}
			dir = getRelation(target, mouseCoords(evt));
			if (!target) {
				return null
			}
			if (dir === "h1" && target.previousSibling) {
				var position = domUtils.getXY(target),
					cellWidth = target.offsetWidth;
				if (Math.abs(position.x + cellWidth - evt.clientX) > cellWidth / 3) {
					target = target.previousSibling
				}
			} else if (dir === "v1" && target.parentNode.previousSibling) {
				var position = domUtils.getXY(target),
					cellHeight = target.offsetHeight;
				if (Math.abs(position.y + cellHeight - evt.clientY) > cellHeight / 3) {
					target = target.parentNode.previousSibling.firstChild
				}
			}
			return target && !(editor.fireEvent("excludetable", target) === true) ? target : null
		}
	};
	UE.UETable.prototype.sortTable = function(sortByCellIndex, compareFn) {
		var table = this.table,
			rows = table.rows,
			trArray = [],
			flag = rows[0].cells[0].tagName === "TH",
			lastRowIndex = 0;
		if (this.selectedTds.length) {
			var range = this.cellsRange,
				len = range.endRowIndex + 1;
			for (var i = range.beginRowIndex; i < len; i++) {
				trArray[i] = rows[i]
			}
			trArray.splice(0, range.beginRowIndex);
			lastRowIndex = range.endRowIndex + 1 === this.rowsNum ? 0 : range.endRowIndex + 1
		} else {
			for (var i = 0, len = rows.length; i < len; i++) {
				trArray[i] = rows[i]
			}
		}
		var Fn = {
			reversecurrent: function(td1, td2) {
				return 1
			},
			orderbyasc: function(td1, td2) {
				var value1 = td1.innerText || td1.textContent,
					value2 = td2.innerText || td2.textContent;
				return value1.localeCompare(value2)
			},
			reversebyasc: function(td1, td2) {
				var value1 = td1.innerHTML,
					value2 = td2.innerHTML;
				return value2.localeCompare(value1)
			},
			orderbynum: function(td1, td2) {
				var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
					value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
				if (value1) value1 = +value1[0];
				if (value2) value2 = +value2[0];
				return (value1 || 0) - (value2 || 0)
			},
			reversebynum: function(td1, td2) {
				var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
					value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
				if (value1) value1 = +value1[0];
				if (value2) value2 = +value2[0];
				return (value2 || 0) - (value1 || 0)
			}
		};
		table.setAttribute("data-sort-type", compareFn && typeof compareFn === "string" && Fn[compareFn] ?
			compareFn : "");
		flag && trArray.splice(0, 1);
		trArray = utils.sort(trArray, function(tr1, tr2) {
			var result;
			if (compareFn && typeof compareFn === "function") {
				result = compareFn.call(this, tr1.cells[sortByCellIndex], tr2.cells[sortByCellIndex])
			} else if (compareFn && typeof compareFn === "number") {
				result = 1
			} else if (compareFn && typeof compareFn === "string" && Fn[compareFn]) {
				result = Fn[compareFn].call(this, tr1.cells[sortByCellIndex], tr2.cells[
					sortByCellIndex])
			} else {
				result = Fn["orderbyasc"].call(this, tr1.cells[sortByCellIndex], tr2.cells[
					sortByCellIndex])
			}
			return result
		});
		var fragment = table.ownerDocument.createDocumentFragment();
		for (var j = 0, len = trArray.length; j < len; j++) {
			fragment.appendChild(trArray[j])
		}
		var tbody = table.getElementsByTagName("tbody")[0];
		if (!lastRowIndex) {
			tbody.appendChild(fragment)
		} else {
			tbody.insertBefore(fragment, rows[lastRowIndex - range.endRowIndex + range.beginRowIndex - 1])
		}
	};
	UE.plugins["tablesort"] = function() {
		var me = this,
			UT = UE.UETable,
			getUETable = function(tdOrTable) {
				return UT.getUETable(tdOrTable)
			},
			getTableItemsByRange = function(editor) {
				return UT.getTableItemsByRange(editor)
			};
		me.ready(function() {
			utils.cssRule("tablesort",
				"table.sortEnabled tr.firstRow th,table.sortEnabled tr.firstRow td{padding-right:20px;background-repeat: no-repeat;background-position: center right;" +
				"   background-image:url(" + me.options.themePath + me.options.theme +
				"/images/sortable.png);}", me.document);
			me.addListener("afterexeccommand", function(type, cmd) {
				if (cmd == "mergeright" || cmd == "mergedown" || cmd == "mergecells") {
					this.execCommand("disablesort")
				}
			})
		});
		UE.commands["sorttable"] = {
			queryCommandState: function() {
				var me = this,
					tableItems = getTableItemsByRange(me);
				if (!tableItems.cell) return -1;
				var table = tableItems.table,
					cells = table.getElementsByTagName("td");
				for (var i = 0, cell; cell = cells[i++];) {
					if (cell.rowSpan != 1 || cell.colSpan != 1) return -1
				}
				return 0
			},
			execCommand: function(cmd, fn) {
				var me = this,
					range = me.selection.getRange(),
					bk = range.createBookmark(true),
					tableItems = getTableItemsByRange(me),
					cell = tableItems.cell,
					ut = getUETable(tableItems.table),
					cellInfo = ut.getCellInfo(cell);
				ut.sortTable(cellInfo.cellIndex, fn);
				range.moveToBookmark(bk);
				try {
					range.select()
				} catch (e) {}
			}
		};
		UE.commands["enablesort"] = UE.commands["disablesort"] = {
			queryCommandState: function(cmd) {
				var table = getTableItemsByRange(this).table;
				if (table && cmd == "enablesort") {
					var cells = domUtils.getElementsByTagName(table, "th td");
					for (var i = 0; i < cells.length; i++) {
						if (cells[i].getAttribute("colspan") > 1 || cells[i].getAttribute("rowspan") >
							1) return -1
					}
				}
				return !table ? -1 : cmd == "enablesort" ^ table.getAttribute("data-sort") !=
					"sortEnabled" ? -1 : 0
			},
			execCommand: function(cmd) {
				var table = getTableItemsByRange(this).table;
				table.setAttribute("data-sort", cmd == "enablesort" ? "sortEnabled" : "sortDisabled");
				cmd == "enablesort" ? domUtils.addClass(table, "sortEnabled") : domUtils.removeClasses(
					table, "sortEnabled")
			}
		}
	};
	UE.plugins["contextmenu"] = function() {
		var me = this;
		me.setOpt("enableContextMenu", me.getOpt("enableContextMenu") || true);
		if (me.getOpt("enableContextMenu") === false) {
			return
		}
		var lang = me.getLang("contextMenu"),
			menu, items = me.options.contextMenu || [{
				label: lang["selectall"],
				cmdName: "selectall"
			}, {
				label: lang.cleardoc,
				cmdName: "cleardoc",
				exec: function() {
					if (confirm(lang.confirmclear)) {
						this.execCommand("cleardoc")
					}
				}
			}, "-", {
				label: lang.unlink,
				cmdName: "unlink"
			}, "-", {
				group: lang.paragraph,
				icon: "justifyjustify",
				subMenu: [{
					label: lang.justifyleft,
					cmdName: "justify",
					value: "left"
				}, {
					label: lang.justifyright,
					cmdName: "justify",
					value: "right"
				}, {
					label: lang.justifycenter,
					cmdName: "justify",
					value: "center"
				}, {
					label: lang.justifyjustify,
					cmdName: "justify",
					value: "justify"
				}]
			}, "-", {
				group: lang.table,
				icon: "table",
				subMenu: [{
					label: lang.inserttable,
					cmdName: "inserttable"
				}, {
					label: lang.deletetable,
					cmdName: "deletetable"
				}, "-", {
					label: lang.deleterow,
					cmdName: "deleterow"
				}, {
					label: lang.deletecol,
					cmdName: "deletecol"
				}, {
					label: lang.insertcol,
					cmdName: "insertcol"
				}, {
					label: lang.insertcolnext,
					cmdName: "insertcolnext"
				}, {
					label: lang.insertrow,
					cmdName: "insertrow"
				}, {
					label: lang.insertrownext,
					cmdName: "insertrownext"
				}, "-", {
					label: lang.insertcaption,
					cmdName: "insertcaption"
				}, {
					label: lang.deletecaption,
					cmdName: "deletecaption"
				}, {
					label: lang.inserttitle,
					cmdName: "inserttitle"
				}, {
					label: lang.deletetitle,
					cmdName: "deletetitle"
				}, {
					label: lang.inserttitlecol,
					cmdName: "inserttitlecol"
				}, {
					label: lang.deletetitlecol,
					cmdName: "deletetitlecol"
				}, "-", {
					label: lang.mergecells,
					cmdName: "mergecells"
				}, {
					label: lang.mergeright,
					cmdName: "mergeright"
				}, {
					label: lang.mergedown,
					cmdName: "mergedown"
				}, "-", {
					label: lang.splittorows,
					cmdName: "splittorows"
				}, {
					label: lang.splittocols,
					cmdName: "splittocols"
				}, {
					label: lang.splittocells,
					cmdName: "splittocells"
				}, "-", {
					label: lang.averageDiseRow,
					cmdName: "averagedistributerow"
				}, {
					label: lang.averageDisCol,
					cmdName: "averagedistributecol"
				}, "-", {
					label: lang.edittd,
					cmdName: "edittd",
					exec: function() {
						if (UE.ui["edittd"]) {
							new UE.ui["edittd"](this)
						}
						this.getDialog("edittd").open()
					}
				}, {
					label: lang.edittable,
					cmdName: "edittable",
					exec: function() {
						if (UE.ui["edittable"]) {
							new UE.ui["edittable"](this)
						}
						this.getDialog("edittable").open()
					}
				}, {
					label: lang.setbordervisible,
					cmdName: "setbordervisible"
				}]
			}, {
				group: lang.tablesort,
				icon: "tablesort",
				subMenu: [{
					label: lang.enablesort,
					cmdName: "enablesort"
				}, {
					label: lang.disablesort,
					cmdName: "disablesort"
				}, "-", {
					label: lang.reversecurrent,
					cmdName: "sorttable",
					value: "reversecurrent"
				}, {
					label: lang.orderbyasc,
					cmdName: "sorttable",
					value: "orderbyasc"
				}, {
					label: lang.reversebyasc,
					cmdName: "sorttable",
					value: "reversebyasc"
				}, {
					label: lang.orderbynum,
					cmdName: "sorttable",
					value: "orderbynum"
				}, {
					label: lang.reversebynum,
					cmdName: "sorttable",
					value: "reversebynum"
				}]
			}, {
				group: lang.borderbk,
				icon: "borderBack",
				subMenu: [{
					label: lang.setcolor,
					cmdName: "interlacetable",
					exec: function() {
						this.execCommand("interlacetable")
					}
				}, {
					label: lang.unsetcolor,
					cmdName: "uninterlacetable",
					exec: function() {
						this.execCommand("uninterlacetable")
					}
				}, {
					label: lang.setbackground,
					cmdName: "settablebackground",
					exec: function() {
						this.execCommand("settablebackground", {
							repeat: true,
							colorList: ["#bbb", "#ccc"]
						})
					}
				}, {
					label: lang.unsetbackground,
					cmdName: "cleartablebackground",
					exec: function() {
						this.execCommand("cleartablebackground")
					}
				}, {
					label: lang.redandblue,
					cmdName: "settablebackground",
					exec: function() {
						this.execCommand("settablebackground", {
							repeat: true,
							colorList: ["red", "blue"]
						})
					}
				}, {
					label: lang.threecolorgradient,
					cmdName: "settablebackground",
					exec: function() {
						this.execCommand("settablebackground", {
							repeat: true,
							colorList: ["#aaa", "#bbb", "#ccc"]
						})
					}
				}]
			}, {
				group: lang.aligntd,
				icon: "aligntd",
				subMenu: [{
					cmdName: "cellalignment",
					value: {
						align: "left",
						vAlign: "top"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "center",
						vAlign: "top"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "right",
						vAlign: "top"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "left",
						vAlign: "middle"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "center",
						vAlign: "middle"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "right",
						vAlign: "middle"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "left",
						vAlign: "bottom"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "center",
						vAlign: "bottom"
					}
				}, {
					cmdName: "cellalignment",
					value: {
						align: "right",
						vAlign: "bottom"
					}
				}]
			}, {
				group: lang.aligntable,
				icon: "aligntable",
				subMenu: [{
					cmdName: "tablealignment",
					className: "left",
					label: lang.tableleft,
					value: "left"
				}, {
					cmdName: "tablealignment",
					className: "center",
					label: lang.tablecenter,
					value: "center"
				}, {
					cmdName: "tablealignment",
					className: "right",
					label: lang.tableright,
					value: "right"
				}]
			}, "-", {
				label: lang.insertparagraphbefore,
				cmdName: "insertparagraph",
				value: true
			}, {
				label: lang.insertparagraphafter,
				cmdName: "insertparagraph"
			}, {
				label: lang["copy"],
				cmdName: "copy"
			}, {
				label: lang["paste"],
				cmdName: "paste"
			}];
		if (!items.length) {
			return
		}
		var uiUtils = UE.ui.uiUtils;
		me.addListener("contextmenu", function(type, evt) {
			var offset = uiUtils.getViewportOffsetByEvent(evt);
			me.fireEvent("beforeselectionchange");
			if (menu) {
				menu.destroy()
			}
			for (var i = 0, ti, contextItems = []; ti = items[i]; i++) {
				var last;
				(function(item) {
					if (item == "-") {
						if ((last = contextItems[contextItems.length - 1]) && last !== "-") {
							contextItems.push("-")
						}
					} else if (item.hasOwnProperty("group")) {
						for (var j = 0, cj, subMenu = []; cj = item.subMenu[j]; j++) {
							(function(subItem) {
								if (subItem == "-") {
									if ((last = subMenu[subMenu.length - 1]) && last !== "-") {
										subMenu.push("-")
									} else {
										subMenu.splice(subMenu.length - 1)
									}
								} else {
									if ((me.commands[subItem.cmdName] || UE.commands[subItem
											.cmdName] || subItem.query) && (subItem.query ?
											subItem.query() : me.queryCommandState(subItem
												.cmdName)) > -1) {
										subMenu.push({
											label: subItem.label || me.getLang(
												"contextMenu." + subItem.cmdName + (
													subItem.value || "")) || "",
											className: "edui-for-" + subItem.cmdName + (
												subItem.className ? " edui-for-" +
												subItem.cmdName + "-" + subItem
												.className : ""),
											onclick: subItem.exec ? function() {
												subItem.exec.call(me)
											} : function() {
												me.execCommand(subItem.cmdName,
													subItem.value)
											}
										})
									}
								}
							})(cj)
						}
						if (subMenu.length) {
							function getLabel() {
								switch (item.icon) {
									case "table":
										return me.getLang("contextMenu.table");
									case "justifyjustify":
										return me.getLang("contextMenu.paragraph");
									case "aligntd":
										return me.getLang("contextMenu.aligntd");
									case "aligntable":
										return me.getLang("contextMenu.aligntable");
									case "tablesort":
										return lang.tablesort;
									case "borderBack":
										return lang.borderbk;
									default:
										return ""
								}
							}
							contextItems.push({
								label: getLabel(),
								className: "edui-for-" + item.icon,
								subMenu: {
									items: subMenu,
									editor: me
								}
							})
						}
					} else {
						if ((me.commands[item.cmdName] || UE.commands[item.cmdName] || item
							.query) && (item.query ? item.query.call(me) : me.queryCommandState(item
								.cmdName)) > -1) {
							contextItems.push({
								label: item.label || me.getLang("contextMenu." + item
									.cmdName),
								className: "edui-for-" + (item.icon ? item.icon : item
									.cmdName + (item.value || "")),
								onclick: item.exec ? function() {
									item.exec.call(me)
								} : function() {
									me.execCommand(item.cmdName, item.value)
								}
							})
						}
					}
				})(ti)
			}
			if (contextItems[contextItems.length - 1] == "-") {
				contextItems.pop()
			}
			menu = new UE.ui.Menu({
				items: contextItems,
				className: "edui-contextmenu",
				editor: me
			});
			menu.render();
			menu.showAt(offset);
			me.fireEvent("aftershowcontextmenu", menu);
			domUtils.preventDefault(evt);
			if (browser.ie) {
				var ieRange;
				try {
					ieRange = me.selection.getNative().createRange()
				} catch (e) {
					return
				}
				if (ieRange.item) {
					var range = new dom.Range(me.document);
					range.selectNode(ieRange.item(0)).select(true, true)
				}
			}
		});
		me.addListener("aftershowcontextmenu", function(type, menu) {
			if (me.zeroclipboard) {
				var items = menu.items;
				for (var key in items) {
					if (items[key].className == "edui-for-copy") {
						me.zeroclipboard.clip(items[key].getDom())
					}
				}
			}
		})
	};
	UE.plugins["shortcutmenu"] = function() {
		var me = this,
			menu, items = me.options.shortcutMenu || [];
		if (!items.length) {
			return
		}
		me.addListener("mouseup", function(type, e) {
			var me = this,
				customEvt = {
					type: type,
					target: e.target || e.srcElement,
					screenX: e.screenX,
					screenY: e.screenY,
					clientX: e.clientX,
					clientY: e.clientY
				};
			setTimeout(function() {
				if (!menu) {
					menu = new baidu.editor.ui.ShortCutMenu({
						editor: me,
						items: items.concat([]),
						theme: me.options.theme,
						className: "edui-shortcutmenu"
					});
					menu.render();
					me.fireEvent("afterrendershortcutmenu", menu)
				}
				menu.show(customEvt, !!UE.plugins["contextmenu"])
			});
			if (type === "contextmenu") {
				domUtils.preventDefault(e);
				if (browser.ie9below) {
					var ieRange;
					try {
						ieRange = me.selection.getNative().createRange()
					} catch (e) {
						return
					}
					if (ieRange.item) {
						var range = new dom.Range(me.document);
						range.selectNode(ieRange.item(0)).select(true, true)
					}
				}
			}
		});
		me.addListener("keydown", function(type) {
			if (type === "keydown") {
				menu && !menu.isHidden && menu.hide()
			}
		})
	};
	UE.plugins["basestyle"] = function() {
		var basestyles = {
				bold: ["strong", "b"],
				italic: ["em", "i"],
				subscript: ["sub"],
				superscript: ["sup"]
			},
			getObj = function(editor, tagNames) {
				return domUtils.filterNodeList(editor.selection.getStartElementPath(), tagNames)
			},
			me = this;
		me.addshortcutkey({
			Bold: "ctrl+66",
			Italic: "ctrl+73",
			Underline: "ctrl+85"
		});
		me.addInputRule(function(root) {
			utils.each(root.getNodesByTagName("b i"), function(node) {
				switch (node.tagName) {
					case "b":
						node.tagName = "strong";
						break;
					case "i":
						node.tagName = "em"
				}
			})
		});
		for (var style in basestyles) {
			(function(cmd, tagNames) {
				me.commands[cmd] = {
					execCommand: function(cmdName) {
						var range = me.selection.getRange(),
							obj = getObj(this, tagNames);
						if (range.collapsed) {
							if (obj) {
								var tmpText = me.document.createTextNode("");
								range.insertNode(tmpText).removeInlineStyle(tagNames);
								range.setStartBefore(tmpText);
								domUtils.remove(tmpText)
							} else {
								var tmpNode = range.document.createElement(tagNames[0]);
								if (cmdName == "superscript" || cmdName == "subscript") {
									tmpText = me.document.createTextNode("");
									range.insertNode(tmpText).removeInlineStyle(["sub", "sup"])
										.setStartBefore(tmpText).collapse(true)
								}
								range.insertNode(tmpNode).setStart(tmpNode, 0)
							}
							range.collapse(true)
						} else {
							if (cmdName == "superscript" || cmdName == "subscript") {
								if (!obj || obj.tagName.toLowerCase() != cmdName) {
									range.removeInlineStyle(["sub", "sup"])
								}
							}
							obj ? range.removeInlineStyle(tagNames) : range.applyInlineStyle(
								tagNames[0])
						}
						range.select()
					},
					queryCommandState: function() {
						return getObj(this, tagNames) ? 1 : 0
					}
				}
			})(style, basestyles[style])
		}
	};
	UE.plugins["elementpath"] = function() {
		var currentLevel, tagNames, me = this;
		me.setOpt("elementPathEnabled", true);
		if (!me.options.elementPathEnabled) {
			return
		}
		me.commands["elementpath"] = {
			execCommand: function(cmdName, level) {
				var start = tagNames[level],
					range = me.selection.getRange();
				currentLevel = level * 1;
				range.selectNode(start).select()
			},
			queryCommandValue: function() {
				var parents = [].concat(this.selection.getStartElementPath()).reverse(),
					names = [];
				tagNames = parents;
				for (var i = 0, ci; ci = parents[i]; i++) {
					if (ci.nodeType == 3) {
						continue
					}
					var name = ci.tagName.toLowerCase();
					if (name == "img" && ci.getAttribute("anchorname")) {
						name = "anchor"
					}
					names[i] = name;
					if (currentLevel == i) {
						currentLevel = -1;
						break
					}
				}
				return names
			}
		}
	};
	UE.plugins["formatmatch"] = function() {
		var me = this,
			list = [],
			img, flag = 0;
		me.addListener("reset", function() {
			list = [];
			flag = 0
		});

		function addList(type, evt) {
			if (browser.webkit) {
				var target = evt.target.tagName == "IMG" ? evt.target : null
			}

			function addFormat(range) {
				if (text) {
					range.selectNode(text)
				}
				return range.applyInlineStyle(list[list.length - 1].tagName, null, list)
			}
			me.undoManger && me.undoManger.save();
			var range = me.selection.getRange(),
				imgT = target || range.getClosedNode();
			if (img && imgT && imgT.tagName == "IMG") {
				imgT.style.cssText += ";float:" + (img.style.cssFloat || img.style.styleFloat || "none") +
					";display:" + (img.style.display || "inline");
				img = null
			} else {
				if (!img) {
					var collapsed = range.collapsed;
					if (collapsed) {
						var text = me.document.createTextNode("match");
						range.insertNode(text).select()
					}
					me.__hasEnterExecCommand = true;
					var removeFormatAttributes = me.options.removeFormatAttributes;
					me.options.removeFormatAttributes = "";
					me.execCommand("removeformat");
					me.options.removeFormatAttributes = removeFormatAttributes;
					me.__hasEnterExecCommand = false;
					range = me.selection.getRange();
					if (list.length) {
						addFormat(range)
					}
					if (text) {
						range.setStartBefore(text).collapse(true)
					}
					range.select();
					text && domUtils.remove(text)
				}
			}
			me.undoManger && me.undoManger.save();
			me.removeListener("mouseup", addList);
			flag = 0
		}
		me.commands["formatmatch"] = {
			execCommand: function(cmdName) {
				if (flag) {
					flag = 0;
					list = [];
					me.removeListener("mouseup", addList);
					return
				}
				var range = me.selection.getRange();
				img = range.getClosedNode();
				if (!img || img.tagName != "IMG") {
					range.collapse(true).shrinkBoundary();
					var start = range.startContainer;
					list = domUtils.findParents(start, true, function(node) {
						return !domUtils.isBlockElm(node) && node.nodeType == 1
					});
					for (var i = 0, ci; ci = list[i]; i++) {
						if (ci.tagName == "A") {
							list.splice(i, 1);
							break
						}
					}
				}
				me.addListener("mouseup", addList);
				flag = 1
			},
			queryCommandState: function() {
				return flag
			},
			notNeedUndo: 1
		}
	};
	UE.plugin.register("searchreplace", function() {
		var me = this;
		var _blockElm = {
			table: 1,
			tbody: 1,
			tr: 1,
			ol: 1,
			ul: 1
		};
		var lastRng = null;

		function getText(node) {
			var text = node.nodeType == 3 ? node.nodeValue : node[browser.ie ? "innerText" : "textContent"];
			return text.replace(domUtils.fillChar, "")
		}

		function findTextInString(textContent, opt, currentIndex) {
			var str = opt.searchStr;
			var reg = new RegExp(str, "g" + (opt.casesensitive ? "" : "i")),
				match;
			if (opt.dir == -1) {
				textContent = textContent.substr(0, currentIndex);
				textContent = textContent.split("").reverse().join("");
				str = str.split("").reverse().join("");
				match = reg.exec(textContent);
				if (match) {
					return currentIndex - match.index - str.length
				}
			} else {
				textContent = textContent.substr(currentIndex);
				match = reg.exec(textContent);
				if (match) {
					return match.index + currentIndex
				}
			}
			return -1
		}

		function findTextBlockElm(node, currentIndex, opt) {
			var textContent, index, methodName = opt.all || opt.dir == 1 ? "getNextDomNode" :
				"getPreDomNode";
			if (domUtils.isBody(node)) {
				node = node.firstChild
			}
			var first = 1;
			while (node) {
				textContent = getText(node);
				index = findTextInString(textContent, opt, currentIndex);
				first = 0;
				if (index != -1) {
					return {
						node: node,
						index: index
					}
				}
				node = domUtils[methodName](node);
				while (node && _blockElm[node.nodeName.toLowerCase()]) {
					node = domUtils[methodName](node, true)
				}
				if (node) {
					currentIndex = opt.dir == -1 ? getText(node).length : 0
				}
			}
		}

		function findNTextInBlockElm(node, index, str) {
			var currentIndex = 0,
				currentNode = node.firstChild,
				currentNodeLength = 0,
				result;
			while (currentNode) {
				if (currentNode.nodeType == 3) {
					currentNodeLength = getText(currentNode).replace(/(^[\t\r\n]+)|([\t\r\n]+$)/, "")
					.length;
					currentIndex += currentNodeLength;
					if (currentIndex >= index) {
						return {
							node: currentNode,
							index: currentNodeLength - (currentIndex - index)
						}
					}
				} else if (!dtd.$empty[currentNode.tagName]) {
					currentNodeLength = getText(currentNode).replace(/(^[\t\r\n]+)|([\t\r\n]+$)/, "")
					.length;
					currentIndex += currentNodeLength;
					if (currentIndex >= index) {
						result = findNTextInBlockElm(currentNode, currentNodeLength - (currentIndex -
							index), str);
						if (result) {
							return result
						}
					}
				}
				currentNode = domUtils.getNextDomNode(currentNode)
			}
		}

		function searchReplace(me, opt) {
			var rng = lastRng || me.selection.getRange(),
				startBlockNode, searchStr = opt.searchStr,
				span = me.document.createElement("span");
			span.innerHTML = "$$ueditor_searchreplace_key$$";
			rng.shrinkBoundary(true);
			if (!rng.collapsed) {
				rng.select();
				var rngText = me.selection.getText();
				if (new RegExp("^" + opt.searchStr + "$", opt.casesensitive ? "" : "i").test(rngText)) {
					if (opt.replaceStr != undefined) {
						replaceText(rng, opt.replaceStr);
						rng.select();
						return true
					} else {
						rng.collapse(opt.dir == -1)
					}
				}
			}
			rng.insertNode(span);
			rng.enlargeToBlockElm(true);
			startBlockNode = rng.startContainer;
			var currentIndex = getText(startBlockNode).indexOf("$$ueditor_searchreplace_key$$");
			rng.setStartBefore(span);
			domUtils.remove(span);
			var result = findTextBlockElm(startBlockNode, currentIndex, opt);
			if (result) {
				var rngStart = findNTextInBlockElm(result.node, result.index, searchStr);
				var rngEnd = findNTextInBlockElm(result.node, result.index + searchStr.length, searchStr);
				rng.setStart(rngStart.node, rngStart.index).setEnd(rngEnd.node, rngEnd.index);
				if (opt.replaceStr !== undefined) {
					replaceText(rng, opt.replaceStr)
				}
				rng.select();
				return true
			} else {
				rng.setCursor()
			}
		}

		function replaceText(rng, str) {
			str = me.document.createTextNode(str);
			rng.deleteContents().insertNode(str)
		}
		return {
			commands: {
				searchreplace: {
					execCommand: function(cmdName, opt) {
						utils.extend(opt, {
							all: false,
							casesensitive: false,
							dir: 1
						}, true);
						var num = 0;
						if (opt.all) {
							lastRng = null;
							var rng = me.selection.getRange(),
								first = me.body.firstChild;
							if (first && first.nodeType == 1) {
								rng.setStart(first, 0);
								rng.shrinkBoundary(true)
							} else if (first.nodeType == 3) {
								rng.setStartBefore(first)
							}
							rng.collapse(true).select(true);
							if (opt.replaceStr !== undefined) {
								me.fireEvent("saveScene")
							}
							while (searchReplace(this, opt)) {
								num++;
								lastRng = me.selection.getRange();
								lastRng.collapse(opt.dir == -1)
							}
							if (num) {
								me.fireEvent("saveScene")
							}
						} else {
							if (opt.replaceStr !== undefined) {
								me.fireEvent("saveScene")
							}
							if (searchReplace(this, opt)) {
								num++;
								lastRng = me.selection.getRange();
								lastRng.collapse(opt.dir == -1)
							}
							if (num) {
								me.fireEvent("saveScene")
							}
						}
						return num
					},
					notNeedUndo: 1
				}
			},
			bindEvents: {
				clearlastSearchResult: function() {
					lastRng = null
				}
			}
		}
	});
	UE.plugins["customstyle"] = function() {
		var me = this;
		me.setOpt({
			customstyle: [{
				tag: "h1",
				name: "tc",
				style: "font-size:32px;line-height:40px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;"
			}, {
				tag: "h1",
				name: "tl",
				style: "font-size:32px;line-height:40px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:left;"
			}, {
				tag: "span",
				name: "im",
				style: "font-size:16px;font-style:italic;font-weight:bold;line-height:18px;"
			}, {
				tag: "span",
				name: "hi",
				style: "font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;"
			}]
		});
		me.commands["customstyle"] = {
			execCommand: function(cmdName, obj) {
				var me = this,
					tagName = obj.tag,
					node = domUtils.findParent(me.selection.getStart(), function(node) {
						return node.getAttribute("label")
					}, true),
					range, bk, tmpObj = {};
				for (var p in obj) {
					if (obj[p] !== undefined) tmpObj[p] = obj[p]
				}
				delete tmpObj.tag;
				if (node && node.getAttribute("label") == obj.label) {
					range = this.selection.getRange();
					bk = range.createBookmark();
					if (range.collapsed) {
						if (dtd.$block[node.tagName]) {
							var fillNode = me.document.createElement("p");
							domUtils.moveChild(node, fillNode);
							node.parentNode.insertBefore(fillNode, node);
							domUtils.remove(node)
						} else {
							domUtils.remove(node, true)
						}
					} else {
						var common = domUtils.getCommonAncestor(bk.start, bk.end),
							nodes = domUtils.getElementsByTagName(common, tagName);
						if (new RegExp(tagName, "i").test(common.tagName)) {
							nodes.push(common)
						}
						for (var i = 0, ni; ni = nodes[i++];) {
							if (ni.getAttribute("label") == obj.label) {
								var ps = domUtils.getPosition(ni, bk.start),
									pe = domUtils.getPosition(ni, bk.end);
								if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils
										.POSITION_CONTAINS) && (pe & domUtils.POSITION_PRECEDING || pe &
										domUtils.POSITION_CONTAINS))
									if (dtd.$block[tagName]) {
										var fillNode = me.document.createElement("p");
										domUtils.moveChild(ni, fillNode);
										ni.parentNode.insertBefore(fillNode, ni)
									} domUtils.remove(ni, true)
							}
						}
						node = domUtils.findParent(common, function(node) {
							return node.getAttribute("label") == obj.label
						}, true);
						if (node) {
							domUtils.remove(node, true)
						}
					}
					range.moveToBookmark(bk).select()
				} else {
					if (dtd.$block[tagName]) {
						this.execCommand("paragraph", tagName, tmpObj, "customstyle");
						range = me.selection.getRange();
						if (!range.collapsed) {
							range.collapse();
							node = domUtils.findParent(me.selection.getStart(), function(node) {
								return node.getAttribute("label") == obj.label
							}, true);
							var pNode = me.document.createElement("p");
							domUtils.insertAfter(node, pNode);
							domUtils.fillNode(me.document, pNode);
							range.setStart(pNode, 0).setCursor()
						}
					} else {
						range = me.selection.getRange();
						if (range.collapsed) {
							node = me.document.createElement(tagName);
							domUtils.setAttributes(node, tmpObj);
							range.insertNode(node).setStart(node, 0).setCursor();
							return
						}
						bk = range.createBookmark();
						range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select()
					}
				}
			},
			queryCommandValue: function() {
				var parent = domUtils.filterNodeList(this.selection.getStartElementPath(), function(
					node) {
					return node.getAttribute("label")
				});
				return parent ? parent.getAttribute("label") : ""
			}
		};
		me.addListener("keyup", function(type, evt) {
			var keyCode = evt.keyCode || evt.which;
			if (keyCode == 32 || keyCode == 13) {
				var range = me.selection.getRange();
				if (range.collapsed) {
					var node = domUtils.findParent(me.selection.getStart(), function(node) {
						return node.getAttribute("label")
					}, true);
					if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
						var p = me.document.createElement("p");
						domUtils.insertAfter(node, p);
						domUtils.fillNode(me.document, p);
						domUtils.remove(node);
						range.setStart(p, 0).setCursor()
					}
				}
			}
		})
	};
	UE.plugins["catchremoteimage"] = function() {
		var me = this,
			ajax = UE.ajax;
		if (me.options.catchRemoteImageEnable === false) {
			return
		}
		me.setOpt({
			catchRemoteImageEnable: false
		});
		var catcherLocalDomain = me.getOpt("catcherLocalDomain"),
			catcherActionUrl = me.getActionUrl(me.getOpt("catcherActionName")),
			catcherUrlPrefix = me.getOpt("catcherUrlPrefix"),
			catcherFieldName = me.getOpt("catcherFieldName");
		me.addListener("serverConfigLoaded", function() {
			catcherLocalDomain = me.getOpt("catcherLocalDomain");
			catcherActionUrl = me.getActionUrl(me.getOpt("catcherActionName"));
			catcherUrlPrefix = me.getOpt("catcherUrlPrefix");
			catcherFieldName = me.getOpt("catcherFieldName")
		});
		me.addListener("afterpaste", function() {
			me.fireEvent("catchremoteimage")
		});
		var catchRemoteImageCatching = false;

		function sendApi(imgs, callbacks) {
			var params = utils.serializeParam(me.queryCommandValue("serverparam")) || "",
				url = utils.formatUrl(catcherActionUrl + (catcherActionUrl.indexOf("?") === -1 ? "?" : "&") +
					params),
				isJsonp = utils.isCrossDomainUrl(url),
				opt = {
					method: "POST",
					dataType: isJsonp ? "jsonp" : "",
					timeout: 6e4,
					headers: me.options.serverHeaders || {},
					onsuccess: callbacks["success"],
					onerror: callbacks["error"]
				};
			opt[catcherFieldName] = imgs;
			ajax.request(url, opt)
		}

		function catchElement(type, ele, imageUrl) {
			sendApi([imageUrl], {
				success: function(r) {
					try {
						var info = r.state !== undefined ? r : eval("(" + r.responseText + ")")
					} catch (e) {
						return
					}
					info = me.options.serverResponsePrepare(info);
					var oldSrc, newSrc, oldBgIMG, newBgIMG, list = info.list;
					var catchFailList = [];
					var catchSuccessList = [];
					var failIMG = me.options.themePath + me.options.theme +
						"/images/img-cracked.png";
					var loadingIMG = me.options.themePath + me.options.theme + "/images/spacer.gif";
					var cj = list[0];
					switch (type) {
						case "image":
							oldSrc = ele.getAttribute("_src") || ele.src || "";
							if (cj.state === "SUCCESS") {
								newSrc = catcherUrlPrefix + cj.url;
								domUtils.removeClasses(ele, "uep-loading");
								domUtils.setAttributes(ele, {
									src: newSrc,
									_src: newSrc,
									"data-catch-result": "success"
								});
								catchSuccessList.push(ele)
							} else {
								domUtils.removeClasses(ele, "uep-loading");
								domUtils.setAttributes(ele, {
									src: failIMG,
									_src: failIMG,
									"data-catch-result": "fail"
								});
								catchFailList.push(ele)
							}
							break;
						case "background":
							oldBgIMG = ele.getAttribute("data-background") || "";
							if (cj.state === "SUCCESS") {
								newBgIMG = catcherUrlPrefix + cj.url;
								ele.style.cssText = ele.style.cssText.replace(loadingIMG, newBgIMG);
								domUtils.removeAttributes(ele, "data-background");
								domUtils.setAttributes(ele, {
									"data-catch-result": "success"
								});
								catchSuccessList.push(ele)
							} else {
								ele.style.cssText = ele.style.cssText.replace(loadingIMG, failIMG);
								domUtils.removeAttributes(ele, "data-background");
								domUtils.setAttributes(ele, {
									"data-catch-result": "fail"
								});
								catchFailList.push(ele)
							}
							break
					}
					me.fireEvent("catchremotesuccess", catchSuccessList, catchFailList);
					catchRemoteImageCatching = false;
					setTimeout(function() {
						me.fireEvent("catchremoteimage")
					}, 0)
				},
				error: function() {
					me.fireEvent("catchremoteerror");
					catchRemoteImageCatching = false;
					setTimeout(function() {
						me.fireEvent("catchremoteimage")
					}, 0)
				}
			})
		}

		function catchRemoteImage() {
			if (catchRemoteImageCatching) {
				return
			}
			catchRemoteImageCatching = true;
			var loadingIMG = me.options.themePath + me.options.theme + "/images/spacer.gif",
				imgs = me.document.querySelectorAll('[style*="url"],img'),
				test = function(src, urls) {
					if (src.indexOf(location.host) !== -1 || /(^\.)|(^\/)/.test(src)) {
						return true
					}
					if (urls) {
						for (var j = 0, url; url = urls[j++];) {
							if (src.indexOf(url) !== -1) {
								return true
							}
						}
					}
					return false
				};
			for (var i = 0, ci; ci = imgs[i++];) {
				if (ci.getAttribute("data-word-image") || ci.getAttribute("data-catch-result")) {
					continue
				}
				if (ci.nodeName === "IMG") {
					var src = ci.getAttribute("_src") || ci.src || "";
					if (/^(https?|ftp):/i.test(src) && !test(src, catcherLocalDomain)) {
						catchElement("image", ci, src);
						domUtils.setAttributes(ci, {
							class: "loadingclass",
							_src: src,
							src: loadingIMG
						});
						return
					}
				} else {
					var backgroundImageurl = ci.style.cssText.replace(/.*\s?url\([\'\"]?/, "").replace(
						/[\'\"]?\).*/, "");
					if (/^(https?|ftp):/i.test(backgroundImageurl) && !test(backgroundImageurl,
							catcherLocalDomain)) {
						catchElement("background", ci, backgroundImageurl);
						ci.style.cssText = ci.style.cssText.replace(backgroundImageurl, loadingIMG);
						domUtils.setAttributes(ci, {
							"data-background": backgroundImageurl
						});
						return
					}
				}
			}
		}
		me.addListener("catchremoteimage", function() {
			catchRemoteImage()
		})
	};
	UE.commands["insertparagraph"] = {
		execCommand: function(cmdName, front) {
			var me = this,
				range = me.selection.getRange(),
				start = range.startContainer,
				tmpNode;
			while (start) {
				if (domUtils.isBody(start)) {
					break
				}
				tmpNode = start;
				start = start.parentNode
			}
			if (tmpNode) {
				var p = me.document.createElement("p");
				if (front) {
					tmpNode.parentNode.insertBefore(p, tmpNode)
				} else {
					tmpNode.parentNode.insertBefore(p, tmpNode.nextSibling)
				}
				domUtils.fillNode(me.document, p);
				range.setStart(p, 0).setCursor(false, true)
			}
		}
	};
	UE.plugins["template"] = function() {
		UE.commands["template"] = {
			execCommand: function(cmd, obj) {
				obj.html && this.execCommand("inserthtml", obj.html)
			}
		};
		this.addListener("click", function(type, evt) {
			var el = evt.target || evt.srcElement,
				range = this.selection.getRange();
			var tnode = domUtils.findParent(el, function(node) {
				if (node.className && domUtils.hasClass(node, "ue_t")) {
					return node
				}
			}, true);
			tnode && range.selectNode(tnode).shrinkBoundary().select()
		});
		this.addListener("keydown", function(type, evt) {
			var range = this.selection.getRange();
			if (!range.collapsed) {
				if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
					var tnode = domUtils.findParent(range.startContainer, function(node) {
						if (node.className && domUtils.hasClass(node, "ue_t")) {
							return node
						}
					}, true);
					if (tnode) {
						domUtils.removeClasses(tnode, ["ue_t"])
					}
				}
			}
		})
	};
	UE.plugin.register("autoupload", function() {
		function sendAndInsertFile(file, editor) {
			var me = editor;
			var fieldName, urlPrefix, maxSize, allowFiles, actionUrl, loadingHtml, errorHandler,
				successHandler, filetype = /image\/\w+/i.test(file.type) ? "image" : "file",
				loadingId = "loading_" + (+new Date).toString(36);
			fieldName = me.getOpt(filetype + "FieldName");
			urlPrefix = me.getOpt(filetype + "UrlPrefix");
			maxSize = me.getOpt(filetype + "MaxSize");
			allowFiles = me.getOpt(filetype + "AllowFiles");
			actionUrl = me.getActionUrl(me.getOpt(filetype + "ActionName"));
			errorHandler = function(title) {
				var loader = me.document.getElementById(loadingId);
				loader && domUtils.remove(loader);
				me.fireEvent("showmessage", {
					id: loadingId,
					content: title,
					type: "error",
					timeout: 4e3
				})
			};
			if (filetype === "image") {
				loadingHtml = '<img class="uep-loading" id="' + loadingId + '" src="' + me.options
					.themePath + me.options.theme + '/images/spacer.gif">';
				successHandler = function(data) {
					var link = urlPrefix + data.url,
						loader = me.document.getElementById(loadingId);
					if (loader) {
						domUtils.removeClasses(loader, "uep-loading");
						loader.setAttribute("src", link);
						loader.setAttribute("_src", link);
						loader.setAttribute("alt", data.original || "");
						loader.removeAttribute("id");
						me.trigger("contentchange", loader)
					}
				}
			} else {
				loadingHtml = "<p>" + '<img class="uep-loading" id="' + loadingId + '" src="' + me.options
					.themePath + me.options.theme + '/images/spacer.gif">' + "</p>";
				successHandler = function(data) {
					var link = urlPrefix + data.url,
						loader = me.document.getElementById(loadingId);
					var rng = me.selection.getRange(),
						bk = rng.createBookmark();
					rng.selectNode(loader).select();
					me.execCommand("insertfile", {
						url: link
					});
					rng.moveToBookmark(bk).select()
				}
			}
			me.execCommand("inserthtml", loadingHtml);
			if (!me.getOpt(filetype + "ActionName")) {
				errorHandler(me.getLang("autoupload.errorLoadConfig"));
				return
			}
			if (file.size > maxSize) {
				errorHandler(me.getLang("autoupload.exceedSizeError"));
				return
			}
			var fileext = file.name ? file.name.substr(file.name.lastIndexOf(".")) : "";
			if (fileext && filetype != "image" || allowFiles && (allowFiles.join("") + ".").indexOf(fileext
					.toLowerCase() + ".") == -1) {
				errorHandler(me.getLang("autoupload.exceedTypeError"));
				return
			}
			var upload = function(file) {
				const formData = new FormData;
				formData.append(fieldName, file, file.name);
				UE.api.requestAction(me, me.getOpt(filetype + "ActionName"), {
					data: formData
				}).then(function(res) {
					successHandler(res.data)
				}).catch(function(err) {
					errorHandler(me.getLang("autoupload.loadError"))
				})
			};
			var imageCompressEnable = me.getOpt("imageCompressEnable"),
				imageMaxSize = me.getOpt("imageMaxSize"),
				imageCompressBorder = me.getOpt("imageCompressBorder");
			if ("image" === filetype && imageCompressEnable) {
				UE.image.compress(file, {
					maxSizeMB: imageMaxSize / 1024 / 1024,
					maxWidthOrHeight: imageCompressBorder
				}).then(function(compressedFile) {
					if (me.options.debug) {
						console.log("AutoUpload.CompressImage", (compressedFile.size / file.size *
							100).toFixed(2) + "%")
					}
					upload(compressedFile)
				}).catch(function(err) {
					console.error("AutoUpload.CompressImage.error", err);
					upload(file)
				})
			} else {
				upload(file)
			}
		}

		function getPasteImage(e) {
			return e.clipboardData && e.clipboardData.items && e.clipboardData.items.length == 1 &&
				/^image\//.test(e.clipboardData.items[0].type) ? e.clipboardData.items : null
		}

		function getDropImage(e) {
			return e.dataTransfer && e.dataTransfer.files ? e.dataTransfer.files : null
		}
		return {
			outputRule: function(root) {
				utils.each(root.getNodesByTagName("img"), function(n) {
					if (/\b(uep\-loading\-error)|(bloaderrorclass)\b/.test(n.getAttr(
						"class"))) {
						n.parentNode.removeChild(n)
					}
				});
				utils.each(root.getNodesByTagName("p"), function(n) {
					if (/\bloadpara\b/.test(n.getAttr("class"))) {
						n.parentNode.removeChild(n)
					}
				})
			},
			bindEvents: {
				defaultOptions: {
					enableDragUpload: true,
					enablePasteUpload: true
				},
				ready: function(e) {
					var me = this;
					if (window.FormData && window.FileReader) {
						var handler = function(e) {
							var hasImg = false,
								items;
							items = e.type == "paste" ? getPasteImage(e) : getDropImage(e);
							if (items) {
								var len = items.length,
									file;
								while (len--) {
									file = items[len];
									if (file.getAsFile) file = file.getAsFile();
									if (file && file.size > 0) {
										sendAndInsertFile(file, me);
										hasImg = true
									}
								}
								hasImg && e.preventDefault()
							}
						};
						if (me.getOpt("enablePasteUpload") !== false) {
							domUtils.on(me.body, "paste ", handler)
						}
						if (me.getOpt("enableDragUpload") !== false) {
							domUtils.on(me.body, "drop", handler);
							domUtils.on(me.body, "dragover", function(e) {
								if (e.dataTransfer.types[0] == "Files") {
									e.preventDefault()
								}
							})
						} else {
							if (browser.gecko) {
								domUtils.on(me.body, "drop", function(e) {
									if (getDropImage(e)) {
										e.preventDefault()
									}
								})
							}
						}
						utils.cssRule("loading",
							".uep-loading{display:inline-block;cursor:default;background: url('" +
							this.options.themePath + this.options.theme +
							"/images/loading.gif') no-repeat center center transparent;border-radius:3px;outline:1px solid #EEE;margin-left:1px;height:22px;width:22px;}\n" +
							".uep-loading-error{display:inline-block;cursor:default;background: url('" +
							this.options.themePath + this.options.theme +
							"/images/loaderror.png') no-repeat center center transparent;border-radius:3px;outline:1px solid #EEE;margin-right:1px;height:22px;width:22px;" +
							"}", this.document)
					}
				}
			}
		}
	});
	UE.plugin.register("section", function() {
		function Section(option) {
			this.tag = "";
			this.level = -1, this.dom = null;
			this.nextSection = null;
			this.previousSection = null;
			this.parentSection = null;
			this.startAddress = [];
			this.endAddress = [];
			this.children = []
		}

		function getSection(option) {
			var section = new Section;
			return utils.extend(section, option)
		}

		function getNodeFromAddress(startAddress, root) {
			var current = root;
			for (var i = 0; i < startAddress.length; i++) {
				if (!current.childNodes) return null;
				current = current.childNodes[startAddress[i]]
			}
			return current
		}
		var me = this;
		return {
			bindMultiEvents: {
				type: "aftersetcontent afterscencerestore",
				handler: function() {
					me.fireEvent("updateSections")
				}
			},
			bindEvents: {
				ready: function() {
					me.fireEvent("updateSections");
					domUtils.on(me.body, "drop paste", function() {
						me.fireEvent("updateSections")
					})
				},
				afterexeccommand: function(type, cmd) {
					if (cmd == "paragraph") {
						me.fireEvent("updateSections")
					}
				},
				keyup: function(type, e) {
					var me = this,
						range = me.selection.getRange();
					if (range.collapsed != true) {
						me.fireEvent("updateSections")
					} else {
						var keyCode = e.keyCode || e.which;
						if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
							me.fireEvent("updateSections")
						}
					}
				}
			},
			commands: {
				getsections: {
					execCommand: function(cmd, levels) {
						var levelFn = levels || ["h1", "h2", "h3", "h4", "h5", "h6"];
						for (var i = 0; i < levelFn.length; i++) {
							if (typeof levelFn[i] == "string") {
								levelFn[i] = function(fn) {
									return function(node) {
										return node.tagName == fn.toUpperCase()
									}
								}(levelFn[i])
							} else if (typeof levelFn[i] != "function") {
								levelFn[i] = function(node) {
									return null
								}
							}
						}

						function getSectionLevel(node) {
							for (var i = 0; i < levelFn.length; i++) {
								if (levelFn[i](node)) return i
							}
							return -1
						}
						var me = this,
							Directory = getSection({
								level: -1,
								title: "root"
							}),
							previous = Directory;

						function traversal(node, Directory) {
							var level, tmpSection = null,
								parent, child, children = node.childNodes;
							for (var i = 0, len = children.length; i < len; i++) {
								child = children[i];
								level = getSectionLevel(child);
								if (level >= 0) {
									var address = me.selection.getRange().selectNode(child)
										.createAddress(true).startAddress,
										current = getSection({
											tag: child.tagName,
											title: child.innerText || child.textContent || "",
											level: level,
											dom: child,
											startAddress: utils.clone(address, []),
											endAddress: utils.clone(address, []),
											children: []
										});
									previous.nextSection = current;
									current.previousSection = previous;
									parent = previous;
									while (level <= parent.level) {
										parent = parent.parentSection
									}
									current.parentSection = parent;
									parent.children.push(current);
									tmpSection = previous = current
								} else {
									child.nodeType === 1 && traversal(child, Directory);
									tmpSection && tmpSection.endAddress[tmpSection.endAddress.length -
										1]++
								}
							}
						}
						traversal(me.body, Directory);
						return Directory
					},
					notNeedUndo: true
				},
				movesection: {
					execCommand: function(cmd, sourceSection, targetSection, isAfter) {
						var me = this,
							targetAddress, target;
						if (!sourceSection || !targetSection || targetSection.level == -1) return;
						targetAddress = isAfter ? targetSection.endAddress : targetSection.startAddress;
						target = getNodeFromAddress(targetAddress, me.body);
						if (!targetAddress || !target || isContainsAddress(sourceSection.startAddress,
								sourceSection.endAddress, targetAddress)) return;
						var startNode = getNodeFromAddress(sourceSection.startAddress, me.body),
							endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
							current, nextNode;
						if (isAfter) {
							current = endNode;
							while (current && !(domUtils.getPosition(startNode, current) & domUtils
									.POSITION_FOLLOWING)) {
								nextNode = current.previousSibling;
								domUtils.insertAfter(target, current);
								if (current == startNode) break;
								current = nextNode
							}
						} else {
							current = startNode;
							while (current && !(domUtils.getPosition(current, endNode) & domUtils
									.POSITION_FOLLOWING)) {
								nextNode = current.nextSibling;
								target.parentNode.insertBefore(current, target);
								if (current == endNode) break;
								current = nextNode
							}
						}
						me.fireEvent("updateSections");

						function isContainsAddress(startAddress, endAddress, addressTarget) {
							var isAfterStartAddress = false,
								isBeforeEndAddress = false;
							for (var i = 0; i < startAddress.length; i++) {
								if (i >= addressTarget.length) break;
								if (addressTarget[i] > startAddress[i]) {
									isAfterStartAddress = true;
									break
								} else if (addressTarget[i] < startAddress[i]) {
									break
								}
							}
							for (var i = 0; i < endAddress.length; i++) {
								if (i >= addressTarget.length) break;
								if (addressTarget[i] < startAddress[i]) {
									isBeforeEndAddress = true;
									break
								} else if (addressTarget[i] > startAddress[i]) {
									break
								}
							}
							return isAfterStartAddress && isBeforeEndAddress
						}
					}
				},
				deletesection: {
					execCommand: function(cmd, section, keepChildren) {
						var me = this;
						if (!section) return;

						function getNodeFromAddress(startAddress) {
							var current = me.body;
							for (var i = 0; i < startAddress.length; i++) {
								if (!current.childNodes) return null;
								current = current.childNodes[startAddress[i]]
							}
							return current
						}
						var startNode = getNodeFromAddress(section.startAddress),
							endNode = getNodeFromAddress(section.endAddress),
							current = startNode,
							nextNode;
						if (!keepChildren) {
							while (current && domUtils.inDoc(endNode, me.document) && !(domUtils
									.getPosition(current, endNode) & domUtils.POSITION_FOLLOWING)) {
								nextNode = current.nextSibling;
								domUtils.remove(current);
								current = nextNode
							}
						} else {
							domUtils.remove(current)
						}
						me.fireEvent("updateSections")
					}
				},
				selectsection: {
					execCommand: function(cmd, section) {
						if (!section && !section.dom) return false;
						var me = this,
							range = me.selection.getRange(),
							address = {
								startAddress: utils.clone(section.startAddress, []),
								endAddress: utils.clone(section.endAddress, [])
							};
						address.endAddress[address.endAddress.length - 1]++;
						range.moveToAddress(address).select().scrollToView();
						return true
					},
					notNeedUndo: true
				},
				scrolltosection: {
					execCommand: function(cmd, section) {
						if (!section && !section.dom) return false;
						var me = this,
							range = me.selection.getRange(),
							address = {
								startAddress: section.startAddress,
								endAddress: section.endAddress
							};
						address.endAddress[address.endAddress.length - 1]++;
						range.moveToAddress(address).scrollToView();
						return true
					},
					notNeedUndo: true
				}
			}
		}
	});
	UE.plugin.register("simpleupload", function() {
		var me = this,
			isLoaded = false,
			containerBtn;

		function initUploadBtn() {
			var input = document.createElement("input");
			input.style.cssText =
				"position:absolute;top:0;left:0;width:100%;height:100%;cursor:pointer;font-size:0;opacity:0;";
			input.type = "file";
			input.accept = me.getOpt("imageAllowFiles").join(",");
			containerBtn.appendChild(input);
			domUtils.on(input, "click", function(e) {
				var toolbarCallback = me.getOpt("toolbarCallback");
				if (toolbarCallback) {
					if (true === toolbarCallback("simpleupload", me)) {
						e.stopPropagation();
						e.preventDefault()
					}
				}
			});
			domUtils.on(input, "change", function(e) {
				var state = me.queryCommandState("simpleupload");
				if (state === -1) {
					return
				}
				if (!input.value) {
					return
				}
				var loadingId = UE.dialog.loadingPlaceholder(me);
				if (!me.getOpt("imageActionName")) {
					UE.dialog.removeLoadingPlaceholder(me, loadingId);
					UE.dialog.tipError(me, me.getLang("autoupload.errorLoadConfig"));
					return
				}
				var allowFiles = me.getOpt("imageAllowFiles");
				var filename = input.value,
					fileext = filename ? filename.substr(filename.lastIndexOf(".")) : "";
				if (!fileext || allowFiles && (allowFiles.join("") + ".").indexOf(fileext
						.toLowerCase() + ".") === -1) {
					UE.dialog.removeLoadingPlaceholder(me, loadingId);
					UE.dialog.tipError(me, me.getLang("autoupload.exceedTypeError"));
					return
				}
				var upload = function(file) {
					const formData = new FormData;
					formData.append(me.getOpt("imageFieldName"), file, file.name);
					UE.api.requestAction(me, me.getOpt("imageActionName"), {
						data: formData
					}).then(function(res) {
						var resData = me.getOpt("serverResponsePrepare")(res.data);
						if ("SUCCESS" === resData.state && resData.url) {
							const loader = me.document.getElementById(loadingId);
							domUtils.removeClasses(loader, "uep-loading");
							const link = me.options.imageUrlPrefix + resData.url;
							loader.setAttribute("src", link);
							loader.setAttribute("_src", link);
							loader.setAttribute("alt", resData.original || "");
							loader.removeAttribute("id");
							me.fireEvent("contentchange");
							me.fireEvent("uploadsuccess", {
								res: resData,
								type: "image"
							})
						} else {
							UE.dialog.removeLoadingPlaceholder(me, loadingId);
							UE.dialog.tipError(me, resData.state)
						}
					}).catch(function(err) {
						UE.dialog.removeLoadingPlaceholder(me, loadingId);
						UE.dialog.tipError(me, err)
					})
				};
				var file = input.files[0];
				var imageCompressEnable = me.getOpt("imageCompressEnable"),
					imageMaxSize = me.getOpt("imageMaxSize"),
					imageCompressBorder = me.getOpt("imageCompressBorder");
				if (imageCompressEnable) {
					UE.image.compress(file, {
						maxSizeMB: imageMaxSize / 1024 / 1024,
						maxWidthOrHeight: imageCompressBorder
					}).then(function(compressedFile) {
						if (me.options.debug) {
							console.log("SimpleUpload.CompressImage", (compressedFile.size /
								file.size * 100).toFixed(2) + "%")
						}
						upload(compressedFile)
					}).catch(function(err) {
						console.error("SimpleUpload.CompressImage.error", err);
						upload(file)
					})
				} else {
					upload(file)
				}
			});
			var stateTimer;
			me.addListener("selectionchange", function() {
				clearTimeout(stateTimer);
				stateTimer = setTimeout(function() {
					var state = me.queryCommandState("simpleupload");
					if (state === -1) {
						input.disabled = "disabled"
					} else {
						input.disabled = false
					}
				}, 400)
			});
			isLoaded = true
		}
		return {
			bindEvents: {
				ready: function() {
					utils.cssRule("loading",
						".uep-loading{display:inline-block;cursor:default;background: url('" + this
						.options.themePath + this.options.theme +
						"/images/loading.gif') no-repeat center center transparent;border-radius:3px;outline:1px solid #EEE;margin-right:1px;height:22px;width:22px;}\n" +
						".uep-loading-error{display:inline-block;cursor:default;background: url('" +
						this.options.themePath + this.options.theme +
						"/images/loaderror.png') no-repeat center center transparent;border-radius:3px;outline:1px solid #EEE;margin-right:1px;height:22px;width:22px;" +
						"}", this.document)
				},
				simpleuploadbtnready: function(type, container) {
					containerBtn = container;
					me.afterConfigReady(initUploadBtn)
				}
			},
			outputRule: function(root) {
				utils.each(root.getNodesByTagName("img"), function(n) {
					if (/\b(uep\-loading\-error)|(bloaderrorclass)\b/.test(n.getAttr(
						"class"))) {
						n.parentNode.removeChild(n)
					}
				})
			},
			commands: {
				simpleupload: {
					queryCommandState: function() {
						return isLoaded ? 0 : -1
					}
				}
			}
		}
	});
	UE.plugin.register("serverparam", function() {
		var me = this,
			serverParam = {};
		return {
			commands: {
				serverparam: {
					execCommand: function(cmd, key, value) {
						if (key === undefined || key === null) {
							serverParam = {}
						} else if (utils.isString(key)) {
							if (value === undefined || value === null) {
								delete serverParam[key]
							} else {
								serverParam[key] = value
							}
						} else if (utils.isObject(key)) {
							utils.extend(serverParam, key, false)
						} else if (utils.isFunction(key)) {
							utils.extend(serverParam, key(), false)
						}
					},
					queryCommandValue: function() {
						return serverParam || {}
					}
				}
			}
		}
	});
	UE.plugin.register("insertfile", function() {
		var me = this;

		function getFileIcon(url) {
			var ext = url.substr(url.lastIndexOf(".") + 1).toLowerCase(),
				maps = {
					ai: "ai.svg",
					apk: "apk.svg",
					chm: "chm.svg",
					css: "css.svg",
					doc: "doc.svg",
					docx: "docx.svg",
					dwg: "dwg.svg",
					gif: "gif.svg",
					html: "html.svg",
					jpeg: "jpeg.svg",
					jpg: "jpg.svg",
					log: "log.svg",
					mp3: "mp3.svg",
					mp4: "mp4.svg",
					pdf: "pdf.svg",
					png: "png.svg",
					ppt: "ppt.svg",
					pptx: "pptx.svg",
					psd: "psd.svg",
					rar: "rar.svg",
					svg: "svg.svg",
					torrent: "torrent.svg",
					txt: "txt.svg",
					unknown: "unknown.svg",
					xls: "xls.svg",
					xlsx: "xlsx.svg",
					zip: "zip.svg"
				};
			return maps[ext] ? maps[ext] : maps["unknown"]
		}
		return {
			commands: {
				insertfile: {
					execCommand: function(command, filelist) {
						filelist = utils.isArray(filelist) ? filelist : [filelist];
						if (me.fireEvent("beforeinsertfile", filelist) === true) {
							return
						}
						var i, item, icon, title, html = "",
							URL = me.getOpt("UEDITOR_HOME_URL"),
							iconDir = me.options.themePath + me.options.theme + "/exts/";
						for (i = 0; i < filelist.length; i++) {
							item = filelist[i];
							icon = iconDir + getFileIcon(item.url);
							title = item.title || item.url.substr(item.url.lastIndexOf("/") + 1);
							html += "<p>" +
								'<a style="background:#EEE;padding:10px;border-radius:5px;line-height:1.5em;display:inline-flex;align-items:center;" href="' +
								item.url + '" title="' + title + '" target="_blank">' +
								'<img style="vertical-align:middle;margin-right:0.5em;height:1.5em;" src="' +
								icon + '" _src="' + icon + '" />' +
								'<span style="color:#111111;line-height:1.5em;flex-grow:1;">' + title +
								"</span>" + "</a>" + "</p>"
						}
						me.execCommand("insertHtml", html);
						me.fireEvent("afterinsertfile", filelist)
					}
				}
			}
		}
	});
	UE.plugins["markdown-shortcut"] = function() {
		if (!UE.browser.chrome) {
			return
		}
		const me = this;
		const getCleanHtml = function(node) {
			let html = node.innerHTML;
			html = html.replace(/[\u200b]*/g, "");
			return html
		};
		let shortCuts = [];
		for (let i = 1; i <= 6; i++) {
			const regExp = new RegExp("^\\t?" + Array(i + 1).join("#") + "(\\s|&nbsp;)");
			(function(command) {
				shortCuts.push({
					name: "Head" + i,
					tagName: ["P"],
					key: [" "],
					offset: [i + 1, i + 2],
					match: [regExp],
					callback: function(param) {
						me.__hasEnterExecCommand = true;
						me.execCommand("paragraph", command);
						let range = me.selection.getRange();
						let node = range.startContainer;
						let html = getCleanHtml(node);
						html = html.replace(regExp, "");
						if (!html) {
							html = domUtils.fillChar
						}
						node.innerHTML = html;
						me.__hasEnterExecCommand = false
					}
				})
			})("h" + i)
		}
		me.on("ready", function() {
			domUtils.on(me.body, "keyup", function(e) {
				let range = me.selection.getRange();
				if (range.endOffset !== range.startOffset) {
					return
				}
				let key = e.key;
				let offset = range.startOffset;
				const node = range.startContainer.parentNode;
				let html = getCleanHtml(node);
				let tagName = node.tagName;
				for (let s of shortCuts) {
					if (!s.tagName.includes(tagName)) {
						continue
					}
					if (!s.key.includes(key)) {
						continue
					}
					if (!s.offset.includes(offset)) {
						continue
					}
					for (let m of s.match) {
						let match = html.match(m);
						if (match) {
							s.callback({
								node: node
							});
							break
						}
					}
				}
			})
		})
	};
	UE.plugins["quick-operate"] = function() {
		if (!UE.browser.chrome) {
			return
		}
		return;
		let me = this;
		const uiUtils = UE.ui.uiUtils;
		me.on("ready", function() {
			let quickOperate = new UE.ui.QuickOperate({
				className: "edui-quick-operate",
				editor: me
			});
			quickOperate.render();
			let quickOperateNode = {
				root: null,
				target: null
			};
			domUtils.on(quickOperate.el, "mouseenter", function(evt) {
				quickOperateNode.root && quickOperateNode.root.classList && quickOperateNode
					.root.classList.add("edui-quick-operate-active")
			});
			domUtils.on(quickOperate.el, "mouseleave", function(evt) {
				quickOperateNode.root && quickOperateNode.root.classList && quickOperateNode
					.root.classList.remove("edui-quick-operate-active")
			});
			domUtils.on(me.body, "mouseout", function(evt) {});
			domUtils.on(me.body, "mouseover", function(evt) {
				const node = evt.target;
				let rootNode = node;
				for (; rootNode.parentNode && rootNode.parentNode.tagName !== "BODY";) {
					rootNode = rootNode.parentNode
				}
				quickOperateNode.root = rootNode;
				quickOperateNode.target = node;
				const rect = node.getBoundingClientRect();
				const offset = uiUtils.getClientRect(node);
				offset.left = offset.left - 55;
				quickOperate.showAt(offset)
			})
		})
	};
	var baidu = baidu || {};
	baidu.editor = baidu.editor || {};
	UE.ui = baidu.editor.ui = {};
	(function() {
		var browser = baidu.editor.browser,
			domUtils = baidu.editor.dom.domUtils;
		var magic = "$EDITORUI";
		var root = window[magic] = {};
		var uidMagic = "ID" + magic;
		var uidCount = 0;
		var uiUtils = baidu.editor.ui.uiUtils = {
			uid: function(obj) {
				return obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount
			},
			hook: function(fn, callback) {
				var dg;
				if (fn && fn._callbacks) {
					dg = fn
				} else {
					dg = function() {
						var q;
						if (fn) {
							q = fn.apply(this, arguments)
						}
						var callbacks = dg._callbacks;
						var k = callbacks.length;
						while (k--) {
							var r = callbacks[k].apply(this, arguments);
							if (q === undefined) {
								q = r
							}
						}
						return q
					};
					dg._callbacks = []
				}
				dg._callbacks.push(callback);
				return dg
			},
			createElementByHtml: function(html) {
				var el = document.createElement("div");
				el.innerHTML = html;
				el = el.firstChild;
				el.parentNode.removeChild(el);
				return el
			},
			getViewportElement: function() {
				return browser.ie && browser.quirks ? document.body : document.documentElement
			},
			getClientRect: function(element) {
				var bcr;
				try {
					bcr = element.getBoundingClientRect()
				} catch (e) {
					bcr = {
						left: 0,
						top: 0,
						height: 0,
						width: 0
					}
				}
				var rect = {
					left: Math.round(bcr.left),
					top: Math.round(bcr.top),
					height: Math.round(bcr.bottom - bcr.top),
					width: Math.round(bcr.right - bcr.left)
				};
				var doc;
				while ((doc = element.ownerDocument) !== document && (element = domUtils.getWindow(doc)
						.frameElement)) {
					bcr = element.getBoundingClientRect();
					rect.left += bcr.left;
					rect.top += bcr.top
				}
				rect.bottom = rect.top + rect.height;
				rect.right = rect.left + rect.width;
				return rect
			},
			getViewportRect: function() {
				var viewportEl = uiUtils.getViewportElement();
				var width = (window.innerWidth || viewportEl.clientWidth) | 0;
				var height = (window.innerHeight || viewportEl.clientHeight) | 0;
				return {
					left: 0,
					top: 0,
					height: height,
					width: width,
					bottom: height,
					right: width
				}
			},
			setViewportOffset: function(element, offset) {
				var rect;
				var fixedLayer = uiUtils.getFixedLayer();
				if (element.parentNode === fixedLayer) {
					element.style.left = offset.left + "px";
					element.style.top = offset.top + "px"
				} else {
					domUtils.setViewportOffset(element, offset)
				}
			},
			getEventOffset: function(evt) {
				var el = evt.target || evt.srcElement;
				var rect = uiUtils.getClientRect(el);
				var offset = uiUtils.getViewportOffsetByEvent(evt);
				return {
					left: offset.left - rect.left,
					top: offset.top - rect.top
				}
			},
			getViewportOffsetByEvent: function(evt) {
				var el = evt.target || evt.srcElement;
				var frameEl = domUtils.getWindow(el).frameElement;
				var offset = {
					left: evt.clientX,
					top: evt.clientY
				};
				if (frameEl && el.ownerDocument !== document) {
					var rect = uiUtils.getClientRect(frameEl);
					offset.left += rect.left;
					offset.top += rect.top
				}
				return offset
			},
			setGlobal: function(id, obj) {
				root[id] = obj;
				return magic + '["' + id + '"]'
			},
			unsetGlobal: function(id) {
				delete root[id]
			},
			copyAttributes: function(tgt, src) {
				var attributes = src.attributes;
				var k = attributes.length;
				while (k--) {
					var attrNode = attributes[k];
					if (attrNode.nodeName != "style" && attrNode.nodeName != "class" && (!browser.ie ||
							attrNode.specified)) {
						tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue)
					}
				}
				if (src.className) {
					domUtils.addClass(tgt, src.className)
				}
				if (src.style.cssText) {
					tgt.style.cssText += ";" + src.style.cssText
				}
			},
			removeStyle: function(el, styleName) {
				if (el.style.removeProperty) {
					el.style.removeProperty(styleName)
				} else if (el.style.removeAttribute) {
					el.style.removeAttribute(styleName)
				} else throw ""
			},
			contains: function(elA, elB) {
				return elA && elB && (elA === elB ? false : elA.contains ? elA.contains(elB) : elA
					.compareDocumentPosition(elB) & 16)
			},
			startDrag: function(evt, callbacks, doc) {
				var doc = doc || document;
				var startX = evt.clientX;
				var startY = evt.clientY;

				function handleMouseMove(evt) {
					var x = evt.clientX - startX;
					var y = evt.clientY - startY;
					callbacks.ondragmove(x, y, evt);
					if (evt.stopPropagation) {
						evt.stopPropagation()
					} else {
						evt.cancelBubble = true
					}
				}
				if (doc.addEventListener) {
					function handleMouseUp(evt) {
						doc.removeEventListener("mousemove", handleMouseMove, true);
						doc.removeEventListener("mouseup", handleMouseUp, true);
						window.removeEventListener("mouseup", handleMouseUp, true);
						callbacks.ondragstop()
					}
					doc.addEventListener("mousemove", handleMouseMove, true);
					doc.addEventListener("mouseup", handleMouseUp, true);
					window.addEventListener("mouseup", handleMouseUp, true);
					evt.preventDefault()
				} else {
					var elm = evt.srcElement;
					elm.setCapture();

					function releaseCaptrue() {
						elm.releaseCapture();
						elm.detachEvent("onmousemove", handleMouseMove);
						elm.detachEvent("onmouseup", releaseCaptrue);
						elm.detachEvent("onlosecaptrue", releaseCaptrue);
						callbacks.ondragstop()
					}
					elm.attachEvent("onmousemove", handleMouseMove);
					elm.attachEvent("onmouseup", releaseCaptrue);
					elm.attachEvent("onlosecaptrue", releaseCaptrue);
					evt.returnValue = false
				}
				callbacks.ondragstart()
			},
			getFixedLayer: function() {
				var layer = document.getElementById("edui_fixedlayer");
				if (layer == null) {
					layer = document.createElement("div");
					layer.id = "edui_fixedlayer";
					document.body.appendChild(layer);
					if (browser.ie && browser.version <= 8) {
						layer.style.position = "absolute";
						bindFixedLayer();
						setTimeout(updateFixedOffset)
					} else {
						layer.style.position = "fixed"
					}
					layer.style.left = "0";
					layer.style.top = "0";
					layer.style.width = "0";
					layer.style.height = "0";
					layer.style.margin = "0"
				}
				return layer
			},
			makeUnselectable: function(element) {
				if (browser.opera || browser.ie && browser.version < 9) {
					element.unselectable = "on";
					if (element.hasChildNodes()) {
						for (var i = 0; i < element.childNodes.length; i++) {
							if (element.childNodes[i].nodeType === 1) {
								uiUtils.makeUnselectable(element.childNodes[i])
							}
						}
					}
				} else {
					if (element.style.MozUserSelect !== undefined) {
						element.style.MozUserSelect = "none"
					} else if (element.style.WebkitUserSelect !== undefined) {
						element.style.WebkitUserSelect = "none"
					} else if (element.style.KhtmlUserSelect !== undefined) {
						element.style.KhtmlUserSelect = "none"
					}
				}
			}
		};

		function updateFixedOffset() {
			var layer = document.getElementById("edui_fixedlayer");
			uiUtils.setViewportOffset(layer, {
				left: 0,
				top: 0
			})
		}

		function bindFixedLayer(adjOffset) {
			domUtils.on(window, "scroll", updateFixedOffset);
			domUtils.on(window, "resize", baidu.editor.utils.defer(updateFixedOffset, 0, true))
		}
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			EventBase = baidu.editor.EventBase,
			UIBase = baidu.editor.ui.UIBase = function() {};
		UIBase.prototype = {
			el: null,
			className: "",
			uiName: "",
			initOptions: function(options) {
				var me = this;
				for (var k in options) {
					me[k] = options[k]
				}
				this.id = this.id || "edui" + uiUtils.uid()
			},
			initUIBase: function() {
				this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this))
			},
			render: function(holder) {
				var html = this.renderHtml();
				var el = uiUtils.createElementByHtml(html);
				var list = domUtils.getElementsByTagName(el, "*");
				var theme = "edui-" + (this.theme || this.editor.options.theme);
				var layer = document.getElementById("edui_fixedlayer");
				for (var i = 0, node; node = list[i++];) {
					domUtils.addClass(node, theme)
				}
				domUtils.addClass(el, theme);
				if (layer) {
					layer.className = "";
					domUtils.addClass(layer, theme)
				}
				var seatEl = this.getDom();
				if (seatEl != null) {
					seatEl.parentNode.replaceChild(el, seatEl);
					uiUtils.copyAttributes(el, seatEl)
				} else {
					if (typeof holder == "string") {
						holder = document.getElementById(holder)
					}
					holder = holder || uiUtils.getFixedLayer();
					domUtils.addClass(holder, theme);
					holder.appendChild(el)
				}
				this.el = el;
				this.postRender()
			},
			getDom: function(name) {
				if (!name) {
					return document.getElementById(this.id)
				} else {
					return document.getElementById(this.id + "_" + name)
				}
			},
			postRender: function() {
				this.fireEvent("postrender")
			},
			getHtmlTpl: function() {
				return ""
			},
			formatHtml: function(tpl) {
				var prefix = "edui-" + this.uiName;
				return tpl.replace(/##/g, this.id).replace(/%%-/g, this.uiName ? prefix + "-" : "")
					.replace(/%%/g, (this.uiName ? prefix : "") + " " + this.className).replace(/\$\$/g,
						this._globalKey)
			},
			renderHtml: function() {
				return this.formatHtml(this.getHtmlTpl())
			},
			dispose: function() {
				var box = this.getDom();
				if (box) baidu.editor.dom.domUtils.remove(box);
				uiUtils.unsetGlobal(this.id)
			},
			uiIsShow: true,
			uiShowStyleBackupValue: null,
			uiShow: function(enable) {
				if (enable) {
					if (this.uiIsShow) {
						return
					}
					this.getDom().style.display = this.uiShowStyleBackupValue;
					this.uiIsShow = true
				} else {
					if (!this.uiIsShow) {
						return
					}
					this.uiShowStyleBackupValue = this.getDom().style.display;
					this.getDom().style.display = "none";
					this.uiIsShow = false
				}
			}
		};
		utils.inherits(UIBase, EventBase)
	})();
	(function() {
		var utils = baidu.editor.utils,
			UIBase = baidu.editor.ui.UIBase,
			Separator = baidu.editor.ui.Separator = function(options) {
				this.initOptions(options);
				this.initSeparator()
			};
		Separator.prototype = {
			uiName: "separator",
			initSeparator: function() {
				this.initUIBase()
			},
			getHtmlTpl: function() {
				return '<div id="##" class="edui-box %%"></div>'
			}
		};
		utils.inherits(Separator, UIBase)
	})();
	(function() {
		var utils = baidu.editor.utils,
			domUtils = baidu.editor.dom.domUtils,
			UIBase = baidu.editor.ui.UIBase,
			uiUtils = baidu.editor.ui.uiUtils;
		var Mask = baidu.editor.ui.Mask = function(options) {
			this.initOptions(options);
			this.initUIBase()
		};
		Mask.prototype = {
			getHtmlTpl: function() {
				return '<div id="##" class="edui-mask %%" onclick="return $$._onClick(event, this);" onmousedown="return $$._onMouseDown(event, this);"></div>'
			},
			postRender: function() {
				var me = this;
				domUtils.on(window, "resize", function() {
					setTimeout(function() {
						if (!me.isHidden()) {
							me._fill()
						}
					})
				})
			},
			show: function(zIndex) {
				this._fill();
				this.getDom().style.display = "";
				this.getDom().style.zIndex = zIndex
			},
			hide: function() {
				this.getDom().style.display = "none";
				this.getDom().style.zIndex = ""
			},
			isHidden: function() {
				return this.getDom().style.display == "none"
			},
			_onMouseDown: function() {
				return false
			},
			_onClick: function(e, target) {
				this.fireEvent("click", e, target)
			},
			_fill: function() {
				var el = this.getDom();
				var vpRect = uiUtils.getViewportRect();
				el.style.width = vpRect.width + "px";
				el.style.height = vpRect.height + "px"
			}
		};
		utils.inherits(Mask, UIBase)
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			domUtils = baidu.editor.dom.domUtils,
			UIBase = baidu.editor.ui.UIBase,
			Popup = baidu.editor.ui.Popup = function(options) {
				this.initOptions(options);
				this.initPopup()
			};
		var allPopups = [];

		function closeAllPopup(evt, el) {
			for (var i = 0; i < allPopups.length; i++) {
				var pop = allPopups[i];
				if (!pop.isHidden()) {
					if (pop.queryAutoHide(el) !== false) {
						if (evt && /scroll/gi.test(evt.type) && pop.className === "edui-wordpastepop") return;
						pop.hide()
					}
				}
			}
			if (allPopups.length) pop.editor.fireEvent("afterhidepop")
		}
		Popup.postHide = closeAllPopup;
		var ANCHOR_CLASSES = ["edui-anchor-topleft", "edui-anchor-topright", "edui-anchor-bottomleft",
			"edui-anchor-bottomright"
		];
		Popup.prototype = {
			SHADOW_RADIUS: 5,
			content: null,
			_hidden: false,
			autoRender: true,
			canSideLeft: true,
			canSideUp: true,
			initPopup: function() {
				this.initUIBase();
				allPopups.push(this)
			},
			getHtmlTpl: function() {
				return '<div id="##" class="edui-popup %%" onmousedown="return false;">' +
					' <div id="##_body" class="edui-popup-body">' +
					' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
					' <div class="edui-shadow"></div>' +
					' <div id="##_content" class="edui-popup-content">' + this.getContentHtmlTpl() +
					"  </div>" + " </div>" + "</div>"
			},
			getContentHtmlTpl: function() {
				if (this.content) {
					if (typeof this.content == "string") {
						return this.content
					}
					return this.content.renderHtml()
				} else {
					return ""
				}
			},
			_UIBase_postRender: UIBase.prototype.postRender,
			postRender: function() {
				if (this.content instanceof UIBase) {
					this.content.postRender()
				}
				if (this.captureWheel && !this.captured) {
					this.captured = true;
					var winHeight = (document.documentElement.clientHeight || document.body
							.clientHeight) - 80,
						_height = this.getDom().offsetHeight,
						_top = uiUtils.getClientRect(this.combox.getDom()).top,
						content = this.getDom("content"),
						ifr = this.getDom("body").getElementsByTagName("iframe"),
						me = this;
					ifr.length && (ifr = ifr[0]);
					while (_top + _height > winHeight) {
						_height -= 30
					}
					content.style.height = _height + "px";
					ifr && (ifr.style.height = _height + "px");
					domUtils.on(content, "onmousewheel" in document.body ? "mousewheel" :
						"DOMMouseScroll",
						function(e) {
							if (e.preventDefault) {
								e.preventDefault()
							} else {
								e.returnValue = false
							}
							if (e.wheelDelta) {
								content.scrollTop -= e.wheelDelta / 120 * 60
							} else {
								content.scrollTop -= e.detail / -3 * 60
							}
						})
				}
				this.fireEvent("postRenderAfter");
				this.hide(true);
				this._UIBase_postRender()
			},
			_doAutoRender: function() {
				if (!this.getDom() && this.autoRender) {
					this.render()
				}
			},
			mesureSize: function() {
				var box = this.getDom("content");
				return uiUtils.getClientRect(box)
			},
			fitSize: function() {
				if (this.captureWheel && this.sized) {
					return this.__size
				}
				this.sized = true;
				var popBodyEl = this.getDom("body");
				popBodyEl.style.width = "";
				popBodyEl.style.height = "";
				var size = this.mesureSize();
				if (this.captureWheel) {
					popBodyEl.style.width = -(-20 - size.width) + "px";
					var height = parseInt(this.getDom("content").style.height, 10);
					!window.isNaN(height) && (size.height = height)
				} else {
					popBodyEl.style.width = size.width + "px"
				}
				popBodyEl.style.height = size.height + "px";
				this.__size = size;
				this.captureWheel && (this.getDom("content").style.overflow = "auto");
				return size
			},
			showAnchor: function(element, hoz) {
				this.showAnchorRect(uiUtils.getClientRect(element), hoz)
			},
			showAnchorRect: function(rect, hoz, adj) {
				this._doAutoRender();
				var vpRect = uiUtils.getViewportRect();
				this.getDom().style.visibility = "hidden";
				this._show();
				var popSize = this.fitSize();
				var sideLeft, sideUp, left, top;
				if (hoz) {
					sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect
						.left > popSize.width);
					sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect
						.bottom > popSize.height);
					left = sideLeft ? rect.left - popSize.width : rect.right;
					top = sideUp ? rect.bottom - popSize.height : rect.top
				} else {
					sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect
						.left > popSize.width);
					sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect
						.bottom > popSize.height);
					left = sideLeft ? rect.right - popSize.width : rect.left;
					top = sideUp ? rect.top - popSize.height : rect.bottom
				}
				if (!sideUp) {
					if (top + popSize.height > vpRect.bottom) {
						top = vpRect.bottom - popSize.height
					}
				}
				var popEl = this.getDom();
				uiUtils.setViewportOffset(popEl, {
					left: left,
					top: top
				});
				domUtils.removeClasses(popEl, ANCHOR_CLASSES);
				popEl.className += " " + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)];
				if (this.editor) {
					popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10;
					baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = popEl.style.zIndex - 1
				}
				this.getDom().style.visibility = "visible"
			},
			showAt: function(offset) {
				var left = offset.left;
				var top = offset.top;
				var rect = {
					left: left,
					top: top,
					right: left,
					bottom: top,
					height: 0,
					width: 0
				};
				this.showAnchorRect(rect, false, true)
			},
			_show: function() {
				if (this._hidden) {
					var box = this.getDom();
					box.style.display = "";
					this._hidden = false;
					this.fireEvent("show")
				}
			},
			isHidden: function() {
				return this._hidden
			},
			show: function() {
				this._doAutoRender();
				this._show()
			},
			hide: function(notNofity) {
				if (!this._hidden && this.getDom()) {
					this.getDom().style.display = "none";
					this._hidden = true;
					if (!notNofity) {
						this.fireEvent("hide")
					}
				}
			},
			queryAutoHide: function(el) {
				return !el || !uiUtils.contains(this.getDom(), el)
			}
		};
		utils.inherits(Popup, UIBase);
		domUtils.on(document, "mousedown", function(evt) {
			var el = evt.target || evt.srcElement;
			closeAllPopup(evt, el)
		});
		domUtils.on(window, "scroll", function(evt, el) {
			closeAllPopup(evt, el)
		})
	})();
	(function() {
		var utils = baidu.editor.utils,
			UIBase = baidu.editor.ui.UIBase,
			ColorPicker = baidu.editor.ui.ColorPicker = function(options) {
				this.initOptions(options);
				this.noColorText = this.noColorText || this.editor.getLang("clearColor");
				this.initUIBase()
			};
		ColorPicker.prototype = {
			getHtmlTpl: function() {
				return genColorPicker(this.noColorText, this.editor)
			},
			_onTableClick: function(evt) {
				var tgt = evt.target || evt.srcElement;
				var color = tgt.getAttribute("data-color");
				if (color) {
					this.fireEvent("pickcolor", color)
				}
			},
			_onTableOver: function(evt) {
				var tgt = evt.target || evt.srcElement;
				var color = tgt.getAttribute("data-color");
				if (color) {
					this.getDom("preview").style.backgroundColor = color
				}
			},
			_onTableOut: function() {
				this.getDom("preview").style.backgroundColor = ""
			},
			_onPickNoColor: function() {
				this.fireEvent("picknocolor")
			},
			_onColorSelect: function(evt) {
				var input = evt.target || evt.srcElement;
				var color = input.value;
				if (color) {
					this.fireEvent("pickcolor", color)
				}
			}
		};
		utils.inherits(ColorPicker, UIBase);
		var COLORS = ("ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646," +
			"f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada," +
			"d8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5," +
			"bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f," +
			"a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09," +
			"7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806," +
			"c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,").split(",");

		function genColorPicker(noColorText, editor) {
			var html = '<div id="##" class="edui-colorpicker %%">' +
				'<div class="edui-colorpicker-topbar edui-clearfix">' +
				'<div id="##_preview" class="edui-colorpicker-preview"><input type="color" id="##_input" onchange="$$._onColorSelect(event,this);" /></div>' +
				'<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">' +
				noColorText + "</div>" + "</div>" +
				'<table  class="edui-box" style="border-collapse: collapse;" onmouseover="$$._onTableOver(event, this);" onmouseout="$$._onTableOut(event, this);" onclick="return $$._onTableClick(event, this);" cellspacing="0" cellpadding="0">' +
				'<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;padding-top: 2px"><td colspan="10">' +
				editor.getLang("themeColor") + "</td> </tr>" + '<tr class="edui-colorpicker-tablefirstrow" >';
			for (var i = 0; i < COLORS.length; i++) {
				if (i && i % 10 === 0) {
					html += "</tr>" + (i == 60 ?
						'<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;"><td colspan="10">' +
						editor.getLang("standardColor") + "</td></tr>" : "") + "<tr" + (i == 60 ?
						' class="edui-colorpicker-tablefirstrow"' : "") + ">"
				}
				html += i < 70 ? '<td style="padding:2px 2px;"><a hidefocus title="' + COLORS[i] +
					'" onclick="return false;" href="javascript:" unselectable="on" class="edui-box edui-colorpicker-colorcell"' +
					' data-color="#' + COLORS[i] + '"' + ' style="background-color:#' + COLORS[i] +
					";border:solid #ccc 1px;" + '"' + "></a></td>" : ""
			}
			html += "</tr>";
			html += "</table></div>";
			return html
		}
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			UIBase = baidu.editor.ui.UIBase;
		var TablePicker = baidu.editor.ui.TablePicker = function(options) {
			this.initOptions(options);
			this.initTablePicker()
		};
		TablePicker.prototype = {
			defaultNumRows: 10,
			defaultNumCols: 10,
			maxNumRows: 20,
			maxNumCols: 20,
			numRows: 10,
			numCols: 10,
			lengthOfCellSide: 22,
			initTablePicker: function() {
				this.initUIBase()
			},
			getHtmlTpl: function() {
				var me = this;
				return '<div id="##" class="edui-tablepicker %%">' +
					'<div class="edui-tablepicker-body">' + '<div class="edui-infoarea">' +
					'<span id="##_label" class="edui-label"></span>' + "</div>" +
					'<div class="edui-pickarea"' + ' onmousemove="$$._onMouseMove(event, this);"' +
					' onmouseover="$$._onMouseOver(event, this);"' +
					' onmouseout="$$._onMouseOut(event, this);"' +
					' onclick="$$._onClick(event, this);"' + ">" +
					'<div id="##_overlay" class="edui-overlay"></div>' + "</div>" + "</div>" + "</div>"
			},
			_UIBase_render: UIBase.prototype.render,
			render: function(holder) {
				this._UIBase_render(holder);
				this.getDom("label").innerHTML = "0" + this.editor.getLang("t_row") + " x 0" + this
					.editor.getLang("t_col")
			},
			_track: function(numCols, numRows) {
				var style = this.getDom("overlay").style;
				var sideLen = this.lengthOfCellSide;
				style.width = numCols * sideLen + "px";
				style.height = numRows * sideLen + "px";
				var label = this.getDom("label");
				label.innerHTML = numCols + this.editor.getLang("t_col") + " x " + numRows + this.editor
					.getLang("t_row");
				this.numCols = numCols;
				this.numRows = numRows
			},
			_onMouseOver: function(evt, el) {
				var rel = evt.relatedTarget || evt.fromElement;
				if (!uiUtils.contains(el, rel) && el !== rel) {
					this.getDom("label").innerHTML = "0" + this.editor.getLang("t_col") + " x 0" + this
						.editor.getLang("t_row");
					this.getDom("overlay").style.visibility = ""
				}
			},
			_onMouseOut: function(evt, el) {
				var rel = evt.relatedTarget || evt.toElement;
				if (!uiUtils.contains(el, rel) && el !== rel) {
					this.getDom("label").innerHTML = "0" + this.editor.getLang("t_col") + " x 0" + this
						.editor.getLang("t_row");
					this.getDom("overlay").style.visibility = "hidden"
				}
			},
			_onMouseMove: function(evt, el) {
				var style = this.getDom("overlay").style;
				var offset = uiUtils.getEventOffset(evt);
				var sideLen = this.lengthOfCellSide;
				var numCols = Math.ceil(offset.left / sideLen);
				var numRows = Math.ceil(offset.top / sideLen);
				this._track(numCols, numRows)
			},
			_onClick: function() {
				this.fireEvent("picktable", this.numCols, this.numRows)
			}
		};
		utils.inherits(TablePicker, UIBase)
	})();
	(function() {
		var browser = baidu.editor.browser,
			domUtils = baidu.editor.dom.domUtils,
			uiUtils = baidu.editor.ui.uiUtils;
		var TPL_STATEFUL = 'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
			' onmouseup="$$.Stateful_onMouseUp(event, this);"' + (browser.ie ?
				' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
				' onmouseleave="$$.Stateful_onMouseLeave(event, this);"' :
				' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
				' onmouseout="$$.Stateful_onMouseOut(event, this);"');
		baidu.editor.ui.Stateful = {
			alwalysHoverable: false,
			target: null,
			Stateful_init: function() {
				this._Stateful_dGetHtmlTpl = this.getHtmlTpl;
				this.getHtmlTpl = this.Stateful_getHtmlTpl
			},
			Stateful_getHtmlTpl: function() {
				var tpl = this._Stateful_dGetHtmlTpl();
				return tpl.replace(/stateful/g, function() {
					return TPL_STATEFUL
				})
			},
			Stateful_onMouseEnter: function(evt, el) {
				this.target = el;
				if (!this.isDisabled() || this.alwalysHoverable) {
					this.addState("hover");
					this.fireEvent("over")
				}
			},
			Stateful_onMouseLeave: function(evt, el) {
				if (!this.isDisabled() || this.alwalysHoverable) {
					this.removeState("hover");
					this.removeState("active");
					this.fireEvent("out")
				}
			},
			Stateful_onMouseOver: function(evt, el) {
				var rel = evt.relatedTarget;
				if (!uiUtils.contains(el, rel) && el !== rel) {
					this.Stateful_onMouseEnter(evt, el)
				}
			},
			Stateful_onMouseOut: function(evt, el) {
				var rel = evt.relatedTarget;
				if (!uiUtils.contains(el, rel) && el !== rel) {
					this.Stateful_onMouseLeave(evt, el)
				}
			},
			Stateful_onMouseDown: function(evt, el) {
				if (!this.isDisabled()) {
					this.addState("active")
				}
			},
			Stateful_onMouseUp: function(evt, el) {
				if (!this.isDisabled()) {
					this.removeState("active")
				}
			},
			Stateful_postRender: function() {
				if (this.disabled && !this.hasState("disabled")) {
					this.addState("disabled")
				}
			},
			hasState: function(state) {
				return domUtils.hasClass(this.getStateDom(), "edui-state-" + state)
			},
			addState: function(state) {
				if (!this.hasState(state)) {
					this.getStateDom().className += " edui-state-" + state
				}
			},
			removeState: function(state) {
				if (this.hasState(state)) {
					domUtils.removeClasses(this.getStateDom(), ["edui-state-" + state])
				}
			},
			getStateDom: function() {
				return this.getDom("state")
			},
			isChecked: function() {
				return this.hasState("checked")
			},
			setChecked: function(checked) {
				if (!this.isDisabled() && checked) {
					this.addState("checked")
				} else {
					this.removeState("checked")
				}
			},
			isDisabled: function() {
				return this.hasState("disabled")
			},
			setDisabled: function(disabled) {
				if (disabled) {
					this.removeState("hover");
					this.removeState("checked");
					this.removeState("active");
					this.addState("disabled")
				} else {
					this.removeState("disabled")
				}
			}
		}
	})();
	(function() {
		var utils = baidu.editor.utils,
			UIBase = baidu.editor.ui.UIBase,
			Stateful = baidu.editor.ui.Stateful,
			Button = baidu.editor.ui.Button = function(options) {
				if (options.name) {
					var btnName = options.name;
					var cssRules = options.cssRules;
					if (!options.className) {
						options.className = "edui-for-" + btnName
					}
					options.cssRules = ".edui-" + (options.theme || "default") +
						" .edui-toolbar .edui-button.edui-for-" + btnName + " .edui-icon {" + cssRules + "}"
				}
				this.initOptions(options);
				this.initButton()
			};
		Button.prototype = {
			uiName: "button",
			label: "",
			title: "",
			showIcon: true,
			showText: true,
			cssRules: "",
			initButton: function() {
				this.initUIBase();
				this.Stateful_init();
				if (this.cssRules) {
					utils.cssRule("edui-customize-" + this.name + "-style", this.cssRules)
				}
			},
			getHtmlTpl: function() {
				return '<div id="##" class="edui-box %%">' + '<div id="##_state" stateful>' +
					'<div class="%%-wrap"><div id="##_body" unselectable="on" ' + (this.title ?
						'title="' + this.title + '"' : "") +
					' class="%%-body" onmousedown="return $$._onMouseDown(event, this);" onclick="return $$._onClick(event, this);">' +
					(this.showIcon ? '<div class="edui-box edui-icon"></div>' : "") + (this.showText ?
						'<div class="edui-box edui-label">' + this.label + "</div>" : "") + "</div>" +
					"</div>" + "</div></div>"
			},
			postRender: function() {
				this.Stateful_postRender();
				this.setDisabled(this.disabled)
			},
			_onMouseDown: function(e) {
				var target = e.target || e.srcElement,
					tagName = target && target.tagName && target.tagName.toLowerCase();
				if (tagName == "input" || tagName == "object" || tagName == "object") {
					return false
				}
			},
			_onClick: function() {
				if (!this.isDisabled()) {
					this.fireEvent("click")
				}
			},
			setTitle: function(text) {
				var label = this.getDom("label");
				label.innerHTML = text
			}
		};
		utils.inherits(Button, UIBase);
		utils.extend(Button.prototype, Stateful)
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			domUtils = baidu.editor.dom.domUtils,
			UIBase = baidu.editor.ui.UIBase,
			Stateful = baidu.editor.ui.Stateful,
			SplitButton = baidu.editor.ui.SplitButton = function(options) {
				this.initOptions(options);
				this.initSplitButton()
			};
		SplitButton.prototype = {
			popup: null,
			uiName: "splitbutton",
			title: "",
			initSplitButton: function() {
				this.initUIBase();
				this.Stateful_init();
				var me = this;
				if (this.popup != null) {
					var popup = this.popup;
					this.popup = null;
					this.setPopup(popup)
				}
			},
			_UIBase_postRender: UIBase.prototype.postRender,
			postRender: function() {
				this.Stateful_postRender();
				this._UIBase_postRender()
			},
			setPopup: function(popup) {
				if (this.popup === popup) return;
				if (this.popup != null) {
					this.popup.dispose()
				}
				popup.addListener("show", utils.bind(this._onPopupShow, this));
				popup.addListener("hide", utils.bind(this._onPopupHide, this));
				popup.addListener("postrender", utils.bind(function() {
					popup.getDom("body").appendChild(uiUtils.createElementByHtml(
						'<div id="' + this.popup.id +
						'_bordereraser" class="edui-bordereraser edui-background" style="width:' +
						(uiUtils.getClientRect(this.getDom()).width + 20) +
						'px"></div>'));
					popup.getDom().className += " " + this.className
				}, this));
				this.popup = popup
			},
			_onPopupShow: function() {
				this.addState("opened")
			},
			_onPopupHide: function() {
				this.removeState("opened")
			},
			getHtmlTpl: function() {
				return '<div id="##" class="edui-box %%">' + "<div " + (this.title ? 'title="' + this
						.title + '"' : "") + ' id="##_state" stateful><div class="%%-body">' +
					'<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
					'<div class="edui-box edui-icon"></div>' + "</div>" +
					'<div class="edui-box edui-splitborder"></div>' +
					'<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
					"</div></div></div>"
			},
			showPopup: function() {
				var rect = uiUtils.getClientRect(this.getDom());
				rect.top -= this.popup.SHADOW_RADIUS;
				rect.height += this.popup.SHADOW_RADIUS;
				this.popup.showAnchorRect(rect)
			},
			_onArrowClick: function(event, el) {
				if (!this.isDisabled()) {
					this.showPopup()
				}
			},
			_onButtonClick: function() {
				if (!this.isDisabled()) {
					this.fireEvent("buttonclick")
				}
			}
		};
		utils.inherits(SplitButton, UIBase);
		utils.extend(SplitButton.prototype, Stateful, true)
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			ColorPicker = baidu.editor.ui.ColorPicker,
			Popup = baidu.editor.ui.Popup,
			SplitButton = baidu.editor.ui.SplitButton,
			ColorButton = baidu.editor.ui.ColorButton = function(options) {
				this.initOptions(options);
				this.initColorButton()
			};
		ColorButton.prototype = {
			initColorButton: function() {
				var me = this;
				this.popup = new Popup({
					content: new ColorPicker({
						noColorText: me.editor.getLang("clearColor"),
						editor: me.editor,
						onpickcolor: function(t, color) {
							me._onPickColor(color)
						},
						onpicknocolor: function(t, color) {
							me._onPickNoColor(color)
						}
					}),
					editor: me.editor
				});
				this.initSplitButton()
			},
			_SplitButton_postRender: SplitButton.prototype.postRender,
			postRender: function() {
				this._SplitButton_postRender();
				this.getDom("button_body").appendChild(uiUtils.createElementByHtml('<div id="' + this
					.id + '_colorlump" class="edui-colorlump"></div>'));
				this.getDom().className += " edui-colorbutton"
			},
			setColor: function(color) {
				this.getDom("colorlump").style.backgroundColor = color;
				this.color = color
			},
			_onPickColor: function(color) {
				if (this.fireEvent("pickcolor", color) !== false) {
					this.setColor(color);
					this.popup.hide()
				}
			},
			_onPickNoColor: function(color) {
				if (this.fireEvent("picknocolor") !== false) {
					this.popup.hide()
				}
			}
		};
		utils.inherits(ColorButton, SplitButton)
	})();
	(function() {
		var utils = baidu.editor.utils,
			Popup = baidu.editor.ui.Popup,
			TablePicker = baidu.editor.ui.TablePicker,
			SplitButton = baidu.editor.ui.SplitButton,
			TableButton = baidu.editor.ui.TableButton = function(options) {
				this.initOptions(options);
				this.initTableButton()
			};
		TableButton.prototype = {
			initTableButton: function() {
				var me = this;
				this.popup = new Popup({
					content: new TablePicker({
						editor: me.editor,
						onpicktable: function(t, numCols, numRows) {
							me._onPickTable(numCols, numRows)
						}
					}),
					editor: me.editor
				});
				this.initSplitButton()
			},
			_onPickTable: function(numCols, numRows) {
				if (this.fireEvent("picktable", numCols, numRows) !== false) {
					this.popup.hide()
				}
			}
		};
		utils.inherits(TableButton, SplitButton)
	})();
	(function() {
		var utils = baidu.editor.utils,
			UIBase = baidu.editor.ui.UIBase;
		var AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker = function(options) {
			this.initOptions(options);
			this.initAutoTypeSetPicker()
		};
		AutoTypeSetPicker.prototype = {
			initAutoTypeSetPicker: function() {
				this.initUIBase()
			},
			getHtmlTpl: function() {
				var me = this.editor,
					opt = me.options.autotypeset,
					lang = me.getLang("autoTypeSet");
				var textAlignInputName = "textAlignValue" + me.uid,
					imageBlockInputName = "imageBlockLineValue" + me.uid,
					symbolConverInputName = "symbolConverValue" + me.uid;
				return '<div id="##" class="edui-autotypesetpicker %%">' +
					'<div class="edui-autotypesetpicker-body">' + "<table >" +
					'<tr><td nowrap><input type="checkbox" name="mergeEmptyline" ' + (opt[
						"mergeEmptyline"] ? "checked" : "") + ">" + lang.mergeLine +
					'</td><td colspan="2"><input type="checkbox" name="removeEmptyline" ' + (opt[
						"removeEmptyline"] ? "checked" : "") + ">" + lang.delLine + "</td></tr>" +
					'<tr><td nowrap><input type="checkbox" name="removeClass" ' + (opt["removeClass"] ?
						"checked" : "") + ">" + lang.removeFormat +
					'</td><td colspan="2"><input type="checkbox" name="indent" ' + (opt["indent"] ?
						"checked" : "") + ">" + lang.indent + "</td></tr>" + "<tr>" +
					'<td nowrap><input type="checkbox" name="textAlign" ' + (opt["textAlign"] ?
						"checked" : "") + ">" + lang.alignment + "</td>" + '<td colspan="2" id="' +
					textAlignInputName + '">' + '<input type="radio" name="' + textAlignInputName +
					'" value="left" ' + (opt["textAlign"] && opt["textAlign"] == "left" ? "checked" :
						"") + ">" + me.getLang("justifyleft") + '<input type="radio" name="' +
					textAlignInputName + '" value="center" ' + (opt["textAlign"] && opt["textAlign"] ==
						"center" ? "checked" : "") + ">" + me.getLang("justifycenter") +
					'<input type="radio" name="' + textAlignInputName + '" value="right" ' + (opt[
						"textAlign"] && opt["textAlign"] == "right" ? "checked" : "") + ">" + me
					.getLang("justifyright") + "</td>" + "</tr>" + "<tr>" +
					'<td nowrap><input type="checkbox" name="imageBlockLine" ' + (opt[
						"imageBlockLine"] ? "checked" : "") + ">" + lang.imageFloat + "</td>" +
					'<td nowrap id="' + imageBlockInputName + '">' + '<input type="radio" name="' +
					imageBlockInputName + '" value="none" ' + (opt["imageBlockLine"] && opt[
						"imageBlockLine"] == "none" ? "checked" : "") + ">" + me.getLang("default") +
					'<input type="radio" name="' + imageBlockInputName + '" value="left" ' + (opt[
						"imageBlockLine"] && opt["imageBlockLine"] == "left" ? "checked" : "") + ">" +
					me.getLang("justifyleft") + '<input type="radio" name="' + imageBlockInputName +
					'" value="center" ' + (opt["imageBlockLine"] && opt["imageBlockLine"] == "center" ?
						"checked" : "") + ">" + me.getLang("justifycenter") +
					'<input type="radio" name="' + imageBlockInputName + '" value="right" ' + (opt[
						"imageBlockLine"] && opt["imageBlockLine"] == "right" ? "checked" : "") + ">" +
					me.getLang("justifyright") + "</td>" + "</tr>" +
					'<tr><td nowrap><input type="checkbox" name="clearFontSize" ' + (opt[
						"clearFontSize"] ? "checked" : "") + ">" + lang.removeFontsize +
					'</td><td colspan="2"><input type="checkbox" name="clearFontFamily" ' + (opt[
						"clearFontFamily"] ? "checked" : "") + ">" + lang.removeFontFamily +
					"</td></tr>" +
					'<tr><td nowrap colspan="3"><input type="checkbox" name="removeEmptyNode" ' + (opt[
						"removeEmptyNode"] ? "checked" : "") + ">" + lang.removeHtml + "</td></tr>" +
					'<tr><td nowrap colspan="3"><input type="checkbox" name="pasteFilter" ' + (opt[
						"pasteFilter"] ? "checked" : "") + ">" + lang.pasteFilter + "</td></tr>" +
					"<tr>" + '<td nowrap><input type="checkbox" name="symbolConver" ' + (opt[
						"bdc2sb"] || opt["tobdc"] ? "checked" : "") + ">" + lang.symbol + "</td>" +
					'<td id="' + symbolConverInputName + '">' +
					'<input type="radio" name="bdc" value="bdc2sb" ' + (opt["bdc2sb"] ? "checked" :
					"") + ">" + lang.bdc2sb + '<input type="radio" name="bdc" value="tobdc" ' + (opt[
						"tobdc"] ? "checked" : "") + ">" + lang.tobdc + "" + "</td>" +
					'<td nowrap align="right"><button >' + lang.run + "</button></td>" + "</tr>" +
					"</table>" + "</div>" + "</div>"
			},
			_UIBase_render: UIBase.prototype.render
		};
		utils.inherits(AutoTypeSetPicker, UIBase)
	})();
	(function() {
		var utils = baidu.editor.utils,
			Popup = baidu.editor.ui.Popup,
			AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
			SplitButton = baidu.editor.ui.SplitButton,
			AutoTypeSetButton = baidu.editor.ui.AutoTypeSetButton = function(options) {
				this.initOptions(options);
				this.initAutoTypeSetButton()
			};

		function getPara(me) {
			var opt = {},
				cont = me.getDom(),
				editorId = me.editor.uid,
				inputType = null,
				attrName = null,
				ipts = domUtils.getElementsByTagName(cont, "input");
			for (var i = ipts.length - 1, ipt; ipt = ipts[i--];) {
				inputType = ipt.getAttribute("type");
				if (inputType == "checkbox") {
					attrName = ipt.getAttribute("name");
					opt[attrName] && delete opt[attrName];
					if (ipt.checked) {
						var attrValue = document.getElementById(attrName + "Value" + editorId);
						if (attrValue) {
							if (/input/gi.test(attrValue.tagName)) {
								opt[attrName] = attrValue.value
							} else {
								var iptChilds = attrValue.getElementsByTagName("input");
								for (var j = iptChilds.length - 1, iptchild; iptchild = iptChilds[j--];) {
									if (iptchild.checked) {
										opt[attrName] = iptchild.value;
										break
									}
								}
							}
						} else {
							opt[attrName] = true
						}
					} else {
						opt[attrName] = false
					}
				} else {
					opt[ipt.getAttribute("value")] = ipt.checked
				}
			}
			var selects = domUtils.getElementsByTagName(cont, "select");
			for (var i = 0, si; si = selects[i++];) {
				var attr = si.getAttribute("name");
				opt[attr] = opt[attr] ? si.value : ""
			}
			utils.extend(me.editor.options.autotypeset, opt);
			me.editor.setPreferences("autotypeset", opt)
		}
		AutoTypeSetButton.prototype = {
			initAutoTypeSetButton: function() {
				var me = this;
				this.popup = new Popup({
					content: new AutoTypeSetPicker({
						editor: me.editor
					}),
					editor: me.editor,
					hide: function() {
						if (!this._hidden && this.getDom()) {
							getPara(this);
							this.getDom().style.display = "none";
							this._hidden = true;
							this.fireEvent("hide")
						}
					}
				});
				var flag = 0;
				this.popup.addListener("postRenderAfter", function() {
					var popupUI = this;
					if (flag) return;
					var cont = this.getDom(),
						btn = cont.getElementsByTagName("button")[0];
					btn.onclick = function() {
						getPara(popupUI);
						me.editor.execCommand("autotypeset");
						popupUI.hide()
					};
					domUtils.on(cont, "click", function(e) {
						var target = e.target || e.srcElement,
							editorId = me.editor.uid;
						if (target && target.tagName == "INPUT") {
							if (target.name == "imageBlockLine" || target.name ==
								"textAlign" || target.name == "symbolConver") {
								var checked = target.checked,
									radioTd = document.getElementById(target.name +
										"Value" + editorId),
									radios = radioTd.getElementsByTagName("input"),
									defalutSelect = {
										imageBlockLine: "none",
										textAlign: "left",
										symbolConver: "tobdc"
									};
								for (var i = 0; i < radios.length; i++) {
									if (checked) {
										if (radios[i].value == defalutSelect[target
												.name]) {
											radios[i].checked = "checked"
										}
									} else {
										radios[i].checked = false
									}
								}
							}
							if (target.name == "imageBlockLineValue" + editorId ||
								target.name == "textAlignValue" + editorId || target
								.name == "bdc") {
								var checkboxs = target.parentNode.previousSibling
									.getElementsByTagName("input");
								checkboxs && (checkboxs[0].checked = true)
							}
							getPara(popupUI)
						}
					});
					flag = 1
				});
				this.initSplitButton()
			}
		};
		utils.inherits(AutoTypeSetButton, SplitButton)
	})();
	(function() {
		var utils = baidu.editor.utils,
			Popup = baidu.editor.ui.Popup,
			Stateful = baidu.editor.ui.Stateful,
			UIBase = baidu.editor.ui.UIBase;
		var CellAlignPicker = baidu.editor.ui.CellAlignPicker = function(options) {
			this.initOptions(options);
			this.initSelected();
			this.initCellAlignPicker()
		};
		CellAlignPicker.prototype = {
			initSelected: function() {
				var status = {
						valign: {
							top: 0,
							middle: 1,
							bottom: 2
						},
						align: {
							left: 0,
							center: 1,
							right: 2
						},
						count: 3
					},
					result = -1;
				if (this.selected) {
					this.selectedIndex = status.valign[this.selected.valign] * status.count + status
						.align[this.selected.align]
				}
			},
			initCellAlignPicker: function() {
				this.initUIBase();
				this.Stateful_init()
			},
			getHtmlTpl: function() {
				var alignType = ["left", "center", "right"],
					COUNT = 9,
					tempClassName = null,
					tempIndex = -1,
					tmpl = [];
				for (var i = 0; i < COUNT; i++) {
					tempClassName = this.selectedIndex === i ? ' class="edui-cellalign-selected" ' : "";
					tempIndex = i % 3;
					tempIndex === 0 && tmpl.push("<tr>");
					tmpl.push('<td index="' + i + '" ' + tempClassName +
						' stateful><div class="edui-icon edui-' + alignType[tempIndex] +
						'"></div></td>');
					tempIndex === 2 && tmpl.push("</tr>")
				}
				return '<div id="##" class="edui-cellalignpicker %%">' +
					'<div class="edui-cellalignpicker-body">' +
					'<table onclick="$$._onClick(event);">' + tmpl.join("") + "</table>" + "</div>" +
					"</div>"
			},
			getStateDom: function() {
				return this.target
			},
			_onClick: function(evt) {
				var target = evt.target || evt.srcElement;
				if (/icon/.test(target.className)) {
					this.items[target.parentNode.getAttribute("index")].onclick();
					Popup.postHide(evt)
				}
			},
			_UIBase_render: UIBase.prototype.render
		};
		utils.inherits(CellAlignPicker, UIBase);
		utils.extend(CellAlignPicker.prototype, Stateful, true)
	})();
	(function() {
		var utils = baidu.editor.utils,
			Stateful = baidu.editor.ui.Stateful,
			uiUtils = baidu.editor.ui.uiUtils,
			UIBase = baidu.editor.ui.UIBase;
		var PastePicker = baidu.editor.ui.PastePicker = function(options) {
			this.initOptions(options);
			this.initPastePicker()
		};
		PastePicker.prototype = {
			initPastePicker: function() {
				this.initUIBase();
				this.Stateful_init()
			},
			getHtmlTpl: function() {
				return '<div class="edui-pasteicon" onclick="$$._onClick(this)"></div>' +
					'<div class="edui-pastecontainer">' + '<div class="edui-title">' + this.editor
					.getLang("pasteOpt") + "</div>" + '<div class="edui-button">' + '<div title="' +
					this.editor.getLang("pasteSourceFormat") +
					'" onclick="$$.format(false)" stateful>' +
					'<div class="edui-richtxticon"></div></div>' + '<div title="' + this.editor.getLang(
						"tagFormat") + '" onclick="$$.format(2)" stateful>' +
					'<div class="edui-tagicon"></div></div>' + '<div title="' + this.editor.getLang(
						"pasteTextFormat") + '" onclick="$$.format(true)" stateful>' +
					'<div class="edui-plaintxticon"></div></div>' + "</div>" + "</div>" + "</div>"
			},
			getStateDom: function() {
				return this.target
			},
			format: function(param) {
				this.editor.ui._isTransfer = true;
				this.editor.fireEvent("pasteTransfer", param)
			},
			_onClick: function(cur) {
				var node = domUtils.getNextDomNode(cur),
					screenHt = uiUtils.getViewportRect().height,
					subPop = uiUtils.getClientRect(node);
				if (subPop.top + subPop.height > screenHt) node.style.top = -subPop.height - cur
					.offsetHeight + "px";
				else node.style.top = "";
				if (/hidden/gi.test(domUtils.getComputedStyle(node, "visibility"))) {
					node.style.visibility = "visible";
					domUtils.addClass(cur, "edui-state-opened")
				} else {
					node.style.visibility = "hidden";
					domUtils.removeClasses(cur, "edui-state-opened")
				}
			},
			_UIBase_render: UIBase.prototype.render
		};
		utils.inherits(PastePicker, UIBase);
		utils.extend(PastePicker.prototype, Stateful, true)
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			UIBase = baidu.editor.ui.UIBase,
			Toolbar = baidu.editor.ui.Toolbar = function(options) {
				this.initOptions(options);
				this.initToolbar()
			};
		Toolbar.prototype = {
			items: null,
			initToolbar: function() {
				this.items = this.items || [];
				this.initUIBase()
			},
			add: function(item, index) {
				if (index === undefined) {
					this.items.push(item)
				} else {
					this.items.splice(index, 0, item)
				}
			},
			getHtmlTpl: function() {
				var buff = [];
				for (var i = 0; i < this.items.length; i++) {
					buff[i] = this.items[i].renderHtml()
				}
				return '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
					buff.join("") + "</div>"
			},
			postRender: function() {
				var box = this.getDom();
				for (var i = 0; i < this.items.length; i++) {
					this.items[i].postRender()
				}
				uiUtils.makeUnselectable(box)
			},
			_onMouseDown: function(e) {
				var target = e.target || e.srcElement,
					tagName = target && target.tagName && target.tagName.toLowerCase();
				if (tagName == "input" || tagName == "object" || tagName == "object") {
					return false
				}
			}
		};
		utils.inherits(Toolbar, UIBase)
	})();
	(function() {
		var utils = baidu.editor.utils,
			domUtils = baidu.editor.dom.domUtils,
			uiUtils = baidu.editor.ui.uiUtils,
			UIBase = baidu.editor.ui.UIBase,
			Popup = baidu.editor.ui.Popup,
			Stateful = baidu.editor.ui.Stateful,
			CellAlignPicker = baidu.editor.ui.CellAlignPicker,
			QuickOperate = baidu.editor.ui.QuickOperate = function(options) {
				this.initOptions(options)
			};
		QuickOperate.prototype = {
			uiName: "quick-operate",
			_Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
			getContentHtmlTpl: function() {
				return ['<div class="edui-quick-operate">', ' <div class="edui-quick-operate-status">',
					'   <div class="edui-quick-operate-icon"><i class="icon icon-image"></i></div>',
					'   <div class="edui-quick-operate-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-icon="DragOutlined"><path d="M8.25 6.5a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5Zm0 7.25a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5Zm1.75 5.5a1.75 1.75 0 1 1-3.5 0 1.75 1.75 0 0 1 3.5 0ZM14.753 6.5a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5ZM16.5 12a1.75 1.75 0 1 1-3.5 0 1.75 1.75 0 0 1 3.5 0Zm-1.747 9a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5Z" fill="currentColor"></path></svg></div>',
					" </div>", ' <div class="edui-quick-operate-menu">',
					'   <div class="item"><i class="icon icon-image"></i> 删除</div>',
					'   <div class="item"><i class="icon icon-image"></i> 左对齐</div>',
					'   <div class="item"><i class="icon icon-image"></i> 右对齐</div>', " </div>",
					"</div>"
				].join("")
			},
			destroy: function() {
				if (this.getDom()) {
					domUtils.remove(this.getDom())
				}
			},
			dispose: function() {
				this.destroy()
			}
		};
		utils.inherits(QuickOperate, Popup)
	})();
	(function() {
		var utils = baidu.editor.utils,
			domUtils = baidu.editor.dom.domUtils,
			uiUtils = baidu.editor.ui.uiUtils,
			UIBase = baidu.editor.ui.UIBase,
			Popup = baidu.editor.ui.Popup,
			Stateful = baidu.editor.ui.Stateful,
			CellAlignPicker = baidu.editor.ui.CellAlignPicker,
			Menu = baidu.editor.ui.Menu = function(options) {
				this.initOptions(options);
				this.initMenu()
			};
		var menuSeparator = {
			renderHtml: function() {
				return '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>'
			},
			postRender: function() {},
			queryAutoHide: function() {
				return true
			}
		};
		Menu.prototype = {
			items: null,
			uiName: "menu",
			initMenu: function() {
				this.items = this.items || [];
				this.initPopup();
				this.initItems()
			},
			initItems: function() {
				for (var i = 0; i < this.items.length; i++) {
					var item = this.items[i];
					if (item == "-") {
						this.items[i] = this.getSeparator()
					} else if (!(item instanceof MenuItem)) {
						item.editor = this.editor;
						item.theme = this.editor.options.theme;
						this.items[i] = this.createItem(item)
					}
				}
			},
			getSeparator: function() {
				return menuSeparator
			},
			createItem: function(item) {
				item.menu = this;
				return new MenuItem(item)
			},
			_Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
			getContentHtmlTpl: function() {
				if (this.items.length == 0) {
					return this._Popup_getContentHtmlTpl()
				}
				var buff = [];
				for (var i = 0; i < this.items.length; i++) {
					var item = this.items[i];
					buff[i] = item.renderHtml()
				}
				return '<div class="%%-body">' + buff.join("") + "</div>"
			},
			_Popup_postRender: Popup.prototype.postRender,
			postRender: function() {
				var me = this;
				for (var i = 0; i < this.items.length; i++) {
					var item = this.items[i];
					item.ownerMenu = this;
					item.postRender()
				}
				domUtils.on(this.getDom(), "mouseover", function(evt) {
					evt = evt || event;
					var rel = evt.relatedTarget || evt.fromElement;
					var el = me.getDom();
					if (!uiUtils.contains(el, rel) && el !== rel) {
						me.fireEvent("over")
					}
				});
				this._Popup_postRender()
			},
			queryAutoHide: function(el) {
				if (el) {
					if (uiUtils.contains(this.getDom(), el)) {
						return false
					}
					for (var i = 0; i < this.items.length; i++) {
						var item = this.items[i];
						if (item.queryAutoHide(el) === false) {
							return false
						}
					}
				}
			},
			clearItems: function() {
				for (var i = 0; i < this.items.length; i++) {
					var item = this.items[i];
					clearTimeout(item._showingTimer);
					clearTimeout(item._closingTimer);
					if (item.subMenu) {
						item.subMenu.destroy()
					}
				}
				this.items = []
			},
			destroy: function() {
				if (this.getDom()) {
					domUtils.remove(this.getDom())
				}
				this.clearItems()
			},
			dispose: function() {
				this.destroy()
			}
		};
		utils.inherits(Menu, Popup);
		var MenuItem = baidu.editor.ui.MenuItem = function(options) {
			this.initOptions(options);
			this.initUIBase();
			this.Stateful_init();
			if (this.subMenu && !(this.subMenu instanceof Menu)) {
				if (options.className && options.className.indexOf("aligntd") != -1) {
					var me = this;
					this.subMenu.selected = this.editor.queryCommandValue("cellalignment");
					this.subMenu = new Popup({
						content: new CellAlignPicker(this.subMenu),
						parentMenu: me,
						editor: me.editor,
						destroy: function() {
							if (this.getDom()) {
								domUtils.remove(this.getDom())
							}
						}
					});
					this.subMenu.addListener("postRenderAfter", function() {
						domUtils.on(this.getDom(), "mouseover", function() {
							me.addState("opened")
						})
					})
				} else {
					this.subMenu = new Menu(this.subMenu)
				}
			}
		};
		MenuItem.prototype = {
			label: "",
			subMenu: null,
			ownerMenu: null,
			uiName: "menuitem",
			alwalysHoverable: true,
			getHtmlTpl: function() {
				return '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
					'<div class="%%-body">' + this.renderLabelHtml() + "</div>" + "</div>"
			},
			postRender: function() {
				var me = this;
				this.addListener("over", function() {
					me.ownerMenu.fireEvent("submenuover", me);
					if (me.subMenu) {
						me.delayShowSubMenu()
					}
				});
				if (this.subMenu) {
					this.getDom().className += " edui-hassubmenu";
					this.subMenu.render();
					this.addListener("out", function() {
						me.delayHideSubMenu()
					});
					this.subMenu.addListener("over", function() {
						clearTimeout(me._closingTimer);
						me._closingTimer = null;
						me.addState("opened")
					});
					this.ownerMenu.addListener("hide", function() {
						me.hideSubMenu()
					});
					this.ownerMenu.addListener("submenuover", function(t, subMenu) {
						if (subMenu !== me) {
							me.delayHideSubMenu()
						}
					});
					this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide;
					this.subMenu.queryAutoHide = function(el) {
						if (el && uiUtils.contains(me.getDom(), el)) {
							return false
						}
						return this._bakQueryAutoHide(el)
					}
				}
				this.getDom().style.tabIndex = "-1";
				uiUtils.makeUnselectable(this.getDom());
				this.Stateful_postRender()
			},
			delayShowSubMenu: function() {
				var me = this;
				if (!me.isDisabled()) {
					me.addState("opened");
					clearTimeout(me._showingTimer);
					clearTimeout(me._closingTimer);
					me._closingTimer = null;
					me._showingTimer = setTimeout(function() {
						me.showSubMenu()
					}, 250)
				}
			},
			delayHideSubMenu: function() {
				var me = this;
				if (!me.isDisabled()) {
					me.removeState("opened");
					clearTimeout(me._showingTimer);
					if (!me._closingTimer) {
						me._closingTimer = setTimeout(function() {
							if (!me.hasState("opened")) {
								me.hideSubMenu()
							}
							me._closingTimer = null
						}, 400)
					}
				}
			},
			renderLabelHtml: function() {
				return '<div class="edui-arrow"></div>' + '<div class="edui-box edui-icon"></div>' +
					'<div class="edui-box edui-label %%-label">' + (this.label || "") + "</div>"
			},
			getStateDom: function() {
				return this.getDom()
			},
			queryAutoHide: function(el) {
				if (this.subMenu && this.hasState("opened")) {
					return this.subMenu.queryAutoHide(el)
				}
			},
			_onClick: function(event, this_) {
				if (this.hasState("disabled")) return;
				if (this.fireEvent("click", event, this_) !== false) {
					if (this.subMenu) {
						this.showSubMenu()
					} else {
						Popup.postHide(event)
					}
				}
			},
			showSubMenu: function() {
				var rect = uiUtils.getClientRect(this.getDom());
				rect.right -= 5;
				rect.left += 2;
				rect.width -= 7;
				rect.top -= 4;
				rect.bottom += 4;
				rect.height += 8;
				this.subMenu.showAnchorRect(rect, true, true)
			},
			hideSubMenu: function() {
				this.subMenu.hide()
			}
		};
		utils.inherits(MenuItem, UIBase);
		utils.extend(MenuItem.prototype, Stateful, true)
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			Menu = baidu.editor.ui.Menu,
			SplitButton = baidu.editor.ui.SplitButton,
			Combox = baidu.editor.ui.Combox = function(options) {
				this.initOptions(options);
				this.initCombox()
			};
		Combox.prototype = {
			uiName: "combox",
			onbuttonclick: function() {
				this.showPopup()
			},
			initCombox: function() {
				var me = this;
				this.items = this.items || [];
				for (var i = 0; i < this.items.length; i++) {
					var item = this.items[i];
					item.uiName = "listitem";
					item.index = i;
					item.onclick = function() {
						me.selectByIndex(this.index)
					}
				}
				this.popup = new Menu({
					items: this.items,
					uiName: "list",
					editor: this.editor,
					captureWheel: true,
					combox: this
				});
				this.initSplitButton()
			},
			_SplitButton_postRender: SplitButton.prototype.postRender,
			postRender: function() {
				this._SplitButton_postRender();
				this.setLabel(this.label || "");
				this.setValue(this.initValue || "")
			},
			showPopup: function() {
				var rect = uiUtils.getClientRect(this.getDom());
				rect.top += 1;
				rect.bottom -= 1;
				rect.height -= 2;
				this.popup.showAnchorRect(rect)
			},
			getValue: function() {
				return this.value
			},
			setValue: function(value) {
				var index = this.indexByValue(value);
				if (index != -1) {
					this.selectedIndex = index;
					this.setLabel(this.items[index].label);
					this.value = this.items[index].value
				} else {
					this.selectedIndex = -1;
					this.setLabel(this.getLabelForUnknowValue(value));
					this.value = value
				}
			},
			setLabel: function(label) {
				this.getDom("button_body").innerHTML = label;
				this.label = label
			},
			getLabelForUnknowValue: function(value) {
				return value
			},
			indexByValue: function(value) {
				for (var i = 0; i < this.items.length; i++) {
					if (value == this.items[i].value) {
						return i
					}
				}
				return -1
			},
			getItem: function(index) {
				return this.items[index]
			},
			selectByIndex: function(index) {
				if (index < this.items.length && this.fireEvent("select", index) !== false) {
					this.selectedIndex = index;
					this.value = this.items[index].value;
					this.setLabel(this.items[index].label)
				}
			}
		};
		utils.inherits(Combox, SplitButton)
	})();
	(function() {
		var utils = baidu.editor.utils,
			domUtils = baidu.editor.dom.domUtils,
			uiUtils = baidu.editor.ui.uiUtils,
			Mask = baidu.editor.ui.Mask,
			UIBase = baidu.editor.ui.UIBase,
			Button = baidu.editor.ui.Button,
			Dialog = baidu.editor.ui.Dialog = function(options) {
				if (options.name) {
					var name = options.name;
					var cssRules = options.cssRules;
					if (!options.className) {
						options.className = "edui-for-" + name
					}
					if (cssRules) {
						options.cssRules = ".edui-for-" + name + " .edui-dialog-content  {" + cssRules + "}"
					}
				}
				this.initOptions(utils.extend({
					autoReset: true,
					draggable: true,
					onok: function() {},
					oncancel: function() {},
					onclose: function(t, ok) {
						return ok ? this.onok() : this.oncancel()
					},
					holdScroll: false
				}, options));
				this.initDialog()
			};
		var modalMask;
		var dragMask;
		var activeDialog;
		Dialog.prototype = {
			draggable: false,
			uiName: "dialog",
			initDialog: function() {
				var me = this,
					theme = this.editor.options.theme;
				if (this.cssRules) {
					this.cssRules = ".edui-" + theme + " " + this.cssRules;
					utils.cssRule("edui-customize-" + this.name + "-style", this.cssRules)
				}
				this.initUIBase();
				this.modalMask = modalMask || (modalMask = new Mask({
					className: "edui-dialog-modalmask",
					theme: theme,
					onclick: function() {
						activeDialog && activeDialog.close(false)
					}
				}));
				this.dragMask = dragMask || (dragMask = new Mask({
					className: "edui-dialog-dragmask",
					theme: theme
				}));
				this.closeButton = new Button({
					className: "edui-dialog-closebutton",
					title: me.closeDialog,
					theme: theme,
					onclick: function() {
						me.close(false)
					}
				});
				this.fullscreen && this.initResizeEvent();
				if (this.buttons) {
					for (var i = 0; i < this.buttons.length; i++) {
						if (!(this.buttons[i] instanceof Button)) {
							this.buttons[i] = new Button(utils.extend(this.buttons[i], {
								editor: this.editor
							}, true))
						}
					}
				}
			},
			initResizeEvent: function() {
				var me = this;
				domUtils.on(window, "resize", function() {
					if (me._hidden || me._hidden === undefined) {
						return
					}
					if (me.__resizeTimer) {
						window.clearTimeout(me.__resizeTimer)
					}
					me.__resizeTimer = window.setTimeout(function() {
						me.__resizeTimer = null;
						var dialogWrapNode = me.getDom(),
							contentNode = me.getDom("content"),
							wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
							contentRect = UE.ui.uiUtils.getClientRect(contentNode),
							vpRect = uiUtils.getViewportRect();
						contentNode.style.width = vpRect.width - wrapRect.width +
							contentRect.width + "px";
						contentNode.style.height = vpRect.height - wrapRect.height +
							contentRect.height + "px";
						dialogWrapNode.style.width = vpRect.width + "px";
						dialogWrapNode.style.height = vpRect.height + "px";
						me.fireEvent("resize")
					}, 100)
				})
			},
			fitSize: function() {
				var popBodyEl = this.getDom("body");
				var $foot = popBodyEl.querySelector(".edui-dialog-foot");
				var heightWithoutBody = 70;
				if (!$foot) {
					heightWithoutBody = 30
				}
				var size = this.mesureSize();
				var winSize = uiUtils.getViewportRect();
				var width = size.width;
				var height = size.height - heightWithoutBody;
				var maxWidth = winSize.width - 2;
				var maxHeight = winSize.height - heightWithoutBody - 2;
				if (width > maxWidth) {
					height = height * maxWidth / width;
					width = maxWidth
				}
				if (height > maxHeight) {
					width = width * maxHeight / height;
					height = maxHeight
				}
				var scale = width / size.width;
				var $content = popBodyEl.querySelector(".edui-dialog-content");
				if (!$content.dataset.dialogScaled) {
					$content.dataset.dialogScaled = true;
					$content.style.width = width + "px";
					$content.style.height = height + "px";
					var $iframe = popBodyEl.querySelector(".edui-dialog-content iframe");
					$iframe.style.width = size.width + "px";
					$iframe.style.height = size.height - heightWithoutBody + "px";
					$iframe.style.transformOrigin = "0 0";
					$iframe.style.transform = "scale(" + scale + ")";
					size.width = width;
					size.height = height + heightWithoutBody
				}
				popBodyEl.style.width = size.width + "px";
				popBodyEl.style.height = size.height + "px";
				return size
			},
			safeSetOffset: function(offset) {
				var me = this;
				var el = me.getDom();
				var vpRect = uiUtils.getViewportRect();
				var rect = uiUtils.getClientRect(el);
				var left = offset.left;
				if (left + rect.width > vpRect.right) {
					left = vpRect.right - rect.width
				}
				var top = offset.top;
				if (top + rect.height > vpRect.bottom) {
					top = vpRect.bottom - rect.height
				}
				el.style.left = Math.max(left, 0) + "px";
				el.style.top = Math.max(top, 0) + "px"
			},
			showAtCenter: function() {
				var vpRect = uiUtils.getViewportRect();
				if (!this.fullscreen) {
					this.getDom().style.display = "";
					var popSize = this.fitSize();
					var titleHeight = this.getDom("titlebar").offsetHeight | 0;
					var left = vpRect.width / 2 - popSize.width / 2;
					var top = vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight;
					var popEl = this.getDom();
					this.safeSetOffset({
						left: Math.max(left | 0, 0),
						top: Math.max(top | 0, 0)
					});
					if (!domUtils.hasClass(popEl, "edui-state-centered")) {
						popEl.className += " edui-state-centered"
					}
				} else {
					var dialogWrapNode = this.getDom(),
						contentNode = this.getDom("content");
					dialogWrapNode.style.display = "block";
					var wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
						contentRect = UE.ui.uiUtils.getClientRect(contentNode);
					dialogWrapNode.style.left = "-100000px";
					contentNode.style.width = vpRect.width - wrapRect.width + contentRect.width + "px";
					contentNode.style.height = vpRect.height - wrapRect.height + contentRect.height +
						"px";
					dialogWrapNode.style.width = vpRect.width + "px";
					dialogWrapNode.style.height = vpRect.height + "px";
					dialogWrapNode.style.left = 0;
					this._originalContext = {
						html: {
							overflowX: document.documentElement.style.overflowX,
							overflowY: document.documentElement.style.overflowY
						},
						body: {
							overflowX: document.body.style.overflowX,
							overflowY: document.body.style.overflowY
						}
					};
					document.documentElement.style.overflowX = "hidden";
					document.documentElement.style.overflowY = "hidden";
					document.body.style.overflowX = "hidden";
					document.body.style.overflowY = "hidden"
				}
				this._show()
			},
			getContentHtml: function() {
				var contentHtml = "";
				if (typeof this.content == "string") {
					contentHtml = this.content
				} else if (this.iframeUrl) {
					contentHtml = '<span id="' + this.id +
						'_contmask" class="dialogcontmask"></span><iframe id="' + this.id +
						'_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="' +
						this.iframeUrl + '"></iframe>'
				}
				return contentHtml
			},
			getHtmlTpl: function() {
				var footHtml = "";
				if (this.buttons) {
					var buff = [];
					for (var i = 0; i < this.buttons.length; i++) {
						buff[i] = this.buttons[i].renderHtml()
					}
					footHtml = '<div class="%%-foot">' + '<div id="##_buttons" class="%%-buttons">' +
						buff.join("") + "</div>" + "</div>"
				}
				return '<div id="##" class="%%"><div ' + (!this.fullscreen ? 'class="%%"' :
						'class="%%-wrap edui-dialog-fullscreen-flag"') +
					'><div id="##_body" class="%%-body">' + '<div class="%%-shadow"></div>' +
					'<div id="##_titlebar" class="%%-titlebar">' +
					'<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
					'<span class="%%-caption">' + (this.title || "") + "</span>" + "</div>" + this
					.closeButton.renderHtml() + "</div>" + '<div id="##_content" class="%%-content">' +
					(this.autoReset ? "" : this.getContentHtml()) + "</div>" + footHtml +
					"</div></div></div>"
			},
			postRender: function() {
				if (!this.modalMask.getDom()) {
					this.modalMask.render();
					this.modalMask.hide()
				}
				if (!this.dragMask.getDom()) {
					this.dragMask.render();
					this.dragMask.hide()
				}
				var me = this;
				this.addListener("show", function() {
					me.modalMask.show(this.getDom().style.zIndex - 2)
				});
				this.addListener("hide", function() {
					me.modalMask.hide()
				});
				if (this.buttons) {
					for (var i = 0; i < this.buttons.length; i++) {
						this.buttons[i].postRender()
					}
				}
				domUtils.on(window, "resize", function() {
					setTimeout(function() {
						if (!me.isHidden()) {
							me.safeSetOffset(uiUtils.getClientRect(me.getDom()))
						}
					})
				});
				this._hide()
			},
			mesureSize: function() {
				var body = this.getDom("body");
				var width = uiUtils.getClientRect(this.getDom("content")).width;
				var dialogBodyStyle = body.style;
				dialogBodyStyle.width = width;
				return uiUtils.getClientRect(body)
			},
			_onTitlebarMouseDown: function(evt, el) {
				if (this.draggable) {
					var rect;
					var vpRect = uiUtils.getViewportRect();
					var me = this;
					uiUtils.startDrag(evt, {
						ondragstart: function() {
							rect = uiUtils.getClientRect(me.getDom());
							me.getDom("contmask").style.visibility = "visible";
							me.dragMask.show(me.getDom().style.zIndex - 1)
						},
						ondragmove: function(x, y) {
							var left = rect.left + x;
							var top = rect.top + y;
							me.safeSetOffset({
								left: left,
								top: top
							})
						},
						ondragstop: function() {
							me.getDom("contmask").style.visibility = "hidden";
							domUtils.removeClasses(me.getDom(), ["edui-state-centered"]);
							me.dragMask.hide()
						}
					})
				}
			},
			reset: function() {
				this.getDom("content").innerHTML = this.getContentHtml();
				this.fireEvent("dialogafterreset")
			},
			_show: function() {
				if (this._hidden) {
					this.getDom().style.display = "";
					this.editor.container.style.zIndex && (this.getDom().style.zIndex = this.editor
						.container.style.zIndex * 1 + 10);
					this._hidden = false;
					this.fireEvent("show");
					baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = this.getDom().style.zIndex -
						4
				}
			},
			isHidden: function() {
				return this._hidden
			},
			_hide: function() {
				if (!this._hidden) {
					var wrapNode = this.getDom();
					wrapNode.style.display = "none";
					wrapNode.style.zIndex = "";
					wrapNode.style.width = "";
					wrapNode.style.height = "";
					this._hidden = true;
					this.fireEvent("hide")
				}
			},
			open: function() {
				if (this.autoReset) {
					try {
						this.reset()
					} catch (e) {
						this.render();
						this.open()
					}
				}
				this.showAtCenter();
				if (this.iframeUrl) {
					try {
						this.getDom("iframe").focus()
					} catch (ex) {}
				}
				activeDialog = this
			},
			_onCloseButtonClick: function(evt, el) {
				this.close(false)
			},
			close: function(ok) {
				if (this.fireEvent("close", ok) !== false) {
					if (this.fullscreen) {
						document.documentElement.style.overflowX = this._originalContext.html.overflowX;
						document.documentElement.style.overflowY = this._originalContext.html.overflowY;
						document.body.style.overflowX = this._originalContext.body.overflowX;
						document.body.style.overflowY = this._originalContext.body.overflowY;
						delete this._originalContext
					}
					this._hide();
					var content = this.getDom("content");
					var iframe = this.getDom("iframe");
					if (content && iframe) {
						var doc = iframe.contentDocument || iframe.contentWindow.document;
						doc && (doc.body.innerHTML = "");
						domUtils.remove(content)
					}
				}
			}
		};
		utils.inherits(Dialog, UIBase)
	})();
	(function() {
		var utils = baidu.editor.utils,
			Menu = baidu.editor.ui.Menu,
			SplitButton = baidu.editor.ui.SplitButton,
			MenuButton = baidu.editor.ui.MenuButton = function(options) {
				this.initOptions(options);
				this.initMenuButton()
			};
		MenuButton.prototype = {
			initMenuButton: function() {
				var me = this;
				this.uiName = "menubutton";
				this.popup = new Menu({
					items: me.items,
					className: me.className,
					editor: me.editor
				});
				this.popup.addListener("show", function() {
					var list = this;
					for (var i = 0; i < list.items.length; i++) {
						list.items[i].removeState("checked");
						if (list.items[i].value == me._value) {
							list.items[i].addState("checked");
							this.value = me._value
						}
					}
				});
				this.initSplitButton()
			},
			setValue: function(value) {
				this._value = value
			}
		};
		utils.inherits(MenuButton, SplitButton)
	})();
	(function() {
		var utils = baidu.editor.utils,
			Popup = baidu.editor.ui.Popup,
			SplitButton = baidu.editor.ui.SplitButton,
			MultiMenuPop = baidu.editor.ui.MultiMenuPop = function(options) {
				this.initOptions(options);
				this.initMultiMenu()
			};
		MultiMenuPop.prototype = {
			initMultiMenu: function() {
				var me = this;
				this.popup = new Popup({
					content: "",
					editor: me.editor,
					iframe_rendered: false,
					onshow: function() {
						if (!this.iframe_rendered) {
							this.iframe_rendered = true;
							this.getDom("content").innerHTML = '<iframe id="' + me.id +
								'_iframe" src="' + me.iframeUrl +
								'" frameborder="0"></iframe>';
							me.editor.container.style.zIndex && (this.getDom().style
								.zIndex = me.editor.container.style.zIndex * 1 + 1)
						}
					}
				});
				this.onbuttonclick = function() {
					this.showPopup()
				};
				this.initSplitButton()
			}
		};
		utils.inherits(MultiMenuPop, SplitButton)
	})();
	(function() {
		var UI = baidu.editor.ui,
			UIBase = UI.UIBase,
			uiUtils = UI.uiUtils,
			utils = baidu.editor.utils,
			domUtils = baidu.editor.dom.domUtils;
		var allMenus = [],
			timeID, isSubMenuShow = false;
		var ShortCutMenu = UI.ShortCutMenu = function(options) {
			this.initOptions(options);
			this.initShortCutMenu()
		};
		ShortCutMenu.postHide = hideAllMenu;
		ShortCutMenu.prototype = {
			isHidden: true,
			SPACE: 5,
			initShortCutMenu: function() {
				this.items = this.items || [];
				this.initUIBase();
				this.initItems();
				this.initEvent();
				allMenus.push(this)
			},
			initEvent: function() {
				var me = this,
					doc = me.editor.document;
				me.editor.addListener("afterhidepop", function() {
					if (!me.isHidden) {
						isSubMenuShow = true
					}
				})
			},
			initItems: function() {
				if (utils.isArray(this.items)) {
					for (var i = 0, len = this.items.length; i < len; i++) {
						if ("string" !== typeof this.items[i]) {
							continue
						}
						var item = this.items[i].toLowerCase();
						if (UI[item]) {
							this.items[i] = new UI[item](this.editor);
							this.items[i].className += " edui-short-cut-sub-menu "
						}
					}
				}
			},
			setOpacity: function(el, value) {
				if (browser.ie && browser.version < 9) {
					el.style.filter = "alpha(opacity = " + parseFloat(value) * 100 + ");"
				} else {
					el.style.opacity = value
				}
			},
			getSubMenuMark: function() {
				isSubMenuShow = false;
				var layerEle = uiUtils.getFixedLayer();
				var list = domUtils.getElementsByTagName(layerEle, "div", function(node) {
					return domUtils.hasClass(node, "edui-short-cut-sub-menu edui-popup")
				});
				for (var i = 0, node; node = list[i++];) {
					if (node.style.display !== "none") {
						isSubMenuShow = true
					}
				}
				return isSubMenuShow
			},
			show: function(e, hasContextmenu) {
				var me = this,
					offset = {},
					el = this.getDom(),
					fixedlayer = uiUtils.getFixedLayer();
				for (let item of this.items) {
					if ("shouldUiShow" in item) {
						item.uiShow(item.shouldUiShow())
					}
				}

				function setPos(offset) {
					if (offset.left < 0) {
						offset.left = 0
					}
					if (offset.top < 0) {
						offset.top = 0
					}
					el.style.cssText = "position:absolute;left:" + offset.left + "px;top:" + offset
						.top + "px;"
				}

				function setPosByCxtMenu(menu) {
					if (!menu.tagName) {
						menu = menu.getDom()
					}
					offset.left = parseInt(menu.style.left);
					offset.top = parseInt(menu.style.top);
					offset.top -= el.offsetHeight + 15;
					setPos(offset)
				}
				me.eventType = e.type;
				el.style.cssText = "display:block;left:-9999px";
				offset = uiUtils.getViewportOffsetByEvent(e);
				offset.top -= el.offsetHeight + me.SPACE;
				offset.left += me.SPACE + 20;
				setPos(offset);
				me.setOpacity(el, 1);
				me.isHidden = false;
				me.left = e.screenX + el.offsetWidth / 2 - me.SPACE;
				me.top = e.screenY - el.offsetHeight / 2 - me.SPACE;
				if (me.editor) {
					el.style.zIndex = me.editor.container.style.zIndex * 1 + 10;
					fixedlayer.style.zIndex = el.style.zIndex - 1
				}
			},
			hide: function() {
				if (this.getDom()) {
					this.getDom().style.display = "none"
				}
				this.isHidden = true
			},
			postRender: function() {
				if (utils.isArray(this.items)) {
					for (var i = 0, item; item = this.items[i++];) {
						item.postRender()
					}
				}
			},
			getHtmlTpl: function() {
				var buff;
				if (utils.isArray(this.items)) {
					buff = [];
					for (var i = 0; i < this.items.length; i++) {
						buff[i] = this.items[i].renderHtml()
					}
					buff = buff.join("")
				} else {
					buff = this.items
				}
				return '<div id="##" class="%% edui-toolbar" data-src="shortcutmenu" onmousedown="return false;" onselectstart="return false;" >' +
					buff + "</div>"
			}
		};
		utils.inherits(ShortCutMenu, UIBase);

		function hideAllMenu(e) {
			var tgt = e.target || e.srcElement,
				cur = domUtils.findParent(tgt, function(node) {
					return domUtils.hasClass(node, "edui-shortcutmenu") || domUtils.hasClass(node,
						"edui-popup")
				}, true);
			if (!cur) {
				for (var i = 0, menu; menu = allMenus[i++];) {
					menu.hide()
				}
			}
		}
		domUtils.on(document, "mousedown", function(e) {
			hideAllMenu(e)
		});
		domUtils.on(window, "scroll", function(e) {
			hideAllMenu(e)
		})
	})();
	(function() {
		var utils = baidu.editor.utils,
			UIBase = baidu.editor.ui.UIBase,
			Breakline = baidu.editor.ui.Breakline = function(options) {
				this.initOptions(options);
				this.initSeparator()
			};
		Breakline.prototype = {
			uiName: "Breakline",
			initSeparator: function() {
				this.initUIBase()
			},
			getHtmlTpl: function() {
				return "<br/>"
			}
		};
		utils.inherits(Breakline, UIBase)
	})();
	(function() {
		var utils = baidu.editor.utils,
			domUtils = baidu.editor.dom.domUtils,
			UIBase = baidu.editor.ui.UIBase,
			Message = baidu.editor.ui.Message = function(options) {
				this.initOptions(options);
				this.initMessage()
			};
		Message.prototype = {
			initMessage: function() {
				this.initUIBase()
			},
			getHtmlTpl: function() {
				return '<div id="##" class="edui-message %%">' +
					' <div id="##_closer" class="edui-message-closer">×</div>' +
					' <div id="##_body" class="edui-message-body edui-message-type-info">' +
					' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
					' <div class="edui-shadow"></div>' +
					' <div id="##_content" class="edui-message-content">' + "  </div>" + " </div>" +
					"</div>"
			},
			reset: function(opt) {
				var me = this;
				if (!opt.keepshow) {
					clearTimeout(this.timer);
					me.timer = setTimeout(function() {
						me.hide()
					}, opt.timeout || 4e3)
				}
				opt.content !== undefined && me.setContent(opt.content);
				opt.type !== undefined && me.setType(opt.type);
				me.show()
			},
			postRender: function() {
				var me = this,
					closer = this.getDom("closer");
				closer && domUtils.on(closer, "click", function() {
					me.hide()
				})
			},
			setContent: function(content) {
				this.getDom("content").innerHTML = content
			},
			setType: function(type) {
				type = type || "info";
				var body = this.getDom("body");
				body.className = body.className.replace(/edui-message-type-[\w-]+/,
					"edui-message-type-" + type)
			},
			getContent: function() {
				return this.getDom("content").innerHTML
			},
			getType: function() {
				var arr = this.getDom("body").match(/edui-message-type-([\w-]+)/);
				return arr ? arr[1] : ""
			},
			show: function() {
				this.getDom().style.display = "block"
			},
			hide: function() {
				var dom = this.getDom();
				if (dom) {
					dom.style.display = "none";
					dom.parentNode && dom.parentNode.removeChild(dom)
				}
			}
		};
		utils.inherits(Message, UIBase)
	})();
	(function() {
		var utils = baidu.editor.utils;
		var editorui = baidu.editor.ui;
		var _Dialog = editorui.Dialog;
		editorui.buttons = {};
		editorui.Dialog = function(options) {
			var dialog = new _Dialog(options);
			dialog.addListener("hide", function() {
				if (dialog.editor) {
					var editor = dialog.editor;
					try {
						if (browser.gecko) {
							var y = editor.window.scrollY,
								x = editor.window.scrollX;
							editor.body.focus();
							editor.window.scrollTo(x, y)
						} else {
							editor.focus()
						}
					} catch (ex) {}
				}
			});
			return dialog
		};
		var btnCmds = ["undo", "redo", "formatmatch", "bold", "italic", "underline", "fontborder",
			"touppercase", "tolowercase", "strikethrough", "subscript", "superscript", "source", "indent",
			"outdent", "blockquote", "pasteplain", "pagebreak", "selectall", "print", "horizontal",
			"removeformat", "time", "date", "unlink", "insertparagraphbeforetable", "insertrow",
			"insertcol", "mergeright", "mergedown", "deleterow", "deletecol", "splittorows", "splittocols",
			"splittocells", "mergecells", "deletetable"
		];
		for (var i = 0, ci; ci = btnCmds[i++];) {
			ci = ci.toLowerCase();
			editorui[ci] = function(cmd) {
				return function(editor) {
					var ui = new editorui.Button({
						className: "edui-for-" + cmd,
						title: editor.options.labelMap[cmd] || editor.getLang("labelMap." +
							cmd) || "",
						onclick: function() {
							editor.execCommand(cmd)
						},
						theme: editor.options.theme,
						showText: false
					});
					switch (cmd) {
						case "bold":
						case "italic":
						case "underline":
						case "strikethrough":
						case "fontborder":
							ui.shouldUiShow = function(cmdInternal) {
								return function() {
									if (!editor.selection.getText()) {
										return false
									}
									return editor.queryCommandState(cmdInternal) !== UE
										.constants.STATEFUL.DISABLED
								}
							}(cmd);
							break
					}
					editorui.buttons[cmd] = ui;
					editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
						var state = editor.queryCommandState(cmd);
						if (state === -1) {
							ui.setDisabled(true);
							ui.setChecked(false)
						} else {
							if (!uiReady) {
								ui.setDisabled(false);
								ui.setChecked(state)
							}
						}
					});
					return ui
				}
			}(ci)
		}
		editorui.cleardoc = function(editor) {
			var ui = new editorui.Button({
				className: "edui-for-cleardoc",
				title: editor.options.labelMap.cleardoc || editor.getLang("labelMap.cleardoc") ||
					"",
				theme: editor.options.theme,
				onclick: function() {
					if (confirm(editor.getLang("confirmClear"))) {
						editor.execCommand("cleardoc")
					}
				}
			});
			editorui.buttons["cleardoc"] = ui;
			editor.addListener("selectionchange", function() {
				ui.setDisabled(editor.queryCommandState("cleardoc") == -1)
			});
			return ui
		};
		var imageTypeSet = ["none", "left", "center", "right"];
		for (let value of imageTypeSet) {
			(function(value) {
				editorui["image" + value] = function(editor) {
					var ui = new editorui.Button({
						className: "edui-for-" + "image" + value,
						title: editor.options.labelMap["image" + value] || editor.getLang(
							"labelMap." + "image" + value) || "",
						theme: editor.options.theme,
						onclick: function() {
							editor.execCommand("imagefloat", value)
						},
						shouldUiShow: function() {
							let closedNode = editor.selection.getRange().getClosedNode();
							if (!closedNode || closedNode.tagName !== "IMG") {
								return false
							}
							if (domUtils.hasClass(closedNode, "uep-loading") || domUtils
								.hasClass(closedNode, "uep-loading-error")) {
								return false
							}
							return editor.queryCommandState("imagefloat") !== UE.constants
								.STATEFUL.DISABLED
						}
					});
					editorui.buttons["image" + value] = ui;
					editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
						ui.setDisabled(editor.queryCommandState("imagefloat") === UE.constants
							.STATEFUL.DISABLED);
						ui.setChecked(editor.queryCommandValue("imagefloat") === value && !
							uiReady)
					});
					return ui
				}
			})(value)
		}
		var typeset = {
			justify: ["left", "right", "center", "justify"],
			directionality: ["ltr", "rtl"]
		};
		for (var p in typeset) {
			(function(cmd, val) {
				for (var i = 0, ci; ci = val[i++];) {
					(function(cmd2) {
						editorui[cmd.replace("float", "") + cmd2] = function(editor) {
							var ui = new editorui.Button({
								className: "edui-for-" + cmd.replace("float", "") + cmd2,
								title: editor.options.labelMap[cmd.replace("float", "") +
									cmd2] || editor.getLang("labelMap." + cmd.replace(
									"float", "") + cmd2) || "",
								theme: editor.options.theme,
								onclick: function() {
									editor.execCommand(cmd, cmd2)
								}
							});
							editorui.buttons[cmd] = ui;
							editor.addListener("selectionchange", function(type, causeByUi,
							uiReady) {
								ui.setDisabled(editor.queryCommandState(cmd) == -1);
								ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !
									uiReady)
							});
							return ui
						}
					})(ci)
				}
			})(p, typeset[p])
		}
		for (var i = 0, ci; ci = ["backcolor", "forecolor"][i++];) {
			editorui[ci] = function(cmd) {
				return function(editor) {
					var ui = new editorui.ColorButton({
						className: "edui-for-" + cmd,
						color: "default",
						title: editor.options.labelMap[cmd] || editor.getLang("labelMap." +
							cmd) || "",
						editor: editor,
						onpickcolor: function(t, color) {
							editor.execCommand(cmd, color)
						},
						onpicknocolor: function() {
							editor.execCommand(cmd, "default");
							this.setColor("transparent");
							this.color = "default"
						},
						onbuttonclick: function() {
							editor.execCommand(cmd, this.color)
						},
						shouldUiShow: function() {
							if (!editor.selection.getText()) {
								return false
							}
							return editor.queryCommandState(cmd) !== UE.constants.STATEFUL
								.DISABLED
						}
					});
					editorui.buttons[cmd] = ui;
					editor.addListener("selectionchange", function() {
						ui.setDisabled(editor.queryCommandState(cmd) == -1)
					});
					return ui
				}
			}(ci)
		}
		var dialogIframeUrlMap = {
			anchor: "~/dialogs/anchor/anchor.html?2f10d082",
			insertimage: "~/dialogs/image/image.html?4da72874",
			link: "~/dialogs/link/link.html?ccbfcf18",
			spechars: "~/dialogs/spechars/spechars.html?3bbeb696",
			searchreplace: "~/dialogs/searchreplace/searchreplace.html?2cb782d2",
			insertvideo: "~/dialogs/video/video.html?aa46c3ba",
			insertaudio: "~/dialogs/audio/audio.html?0742e32d",
			help: "~/dialogs/help/help.html?05c0c8bf",
			preview: "~/dialogs/preview/preview.html?5d9a0847",
			emotion: "~/dialogs/emotion/emotion.html?a7bc0989",
			wordimage: "~/dialogs/wordimage/wordimage.html?30a3bf2b",
			formula: "~/dialogs/formula/formula.html?9a5a1511",
			attachment: "~/dialogs/attachment/attachment.html?2cf57519",
			insertframe: "~/dialogs/insertframe/insertframe.html?807119a5",
			edittip: "~/dialogs/table/edittip.html?fa0ea189",
			edittable: "~/dialogs/table/edittable.html?134e2f06",
			edittd: "~/dialogs/table/edittd.html?9fe1a06e",
			scrawl: "~/dialogs/scrawl/scrawl.html?81bccab9",
			template: "~/dialogs/template/template.html?3c8090b7",
			background: "~/dialogs/background/background.html?c2bb8b05",
			contentimport: "~/dialogs/contentimport/contentimport.html?e298f77b"
		};
		var dialogBtns = {
			noOk: ["searchreplace", "help", "spechars", "preview"],
			ok: ["attachment", "anchor", "link", "insertimage", "insertframe", "wordimage", "insertvideo",
				"insertaudio", "edittip", "edittable", "edittd", "scrawl", "template", "formula",
				"background", "contentimport"
			]
		};
		for (var p in dialogBtns) {
			(function(type, vals) {
				for (var i = 0, ci; ci = vals[i++];) {
					if (browser.opera && ci === "searchreplace") {
						continue
					}(function(cmd) {
						editorui[cmd] = function(editor, iframeUrl, title) {
							iframeUrl = iframeUrl || (editor.options.dialogIframeUrlMap || {})[
								cmd] || dialogIframeUrlMap[cmd];
							title = editor.options.labelMap[cmd] || editor.getLang("labelMap." +
								cmd) || "";
							var dialog;
							if (iframeUrl) {
								dialog = new editorui.Dialog(utils.extend({
									iframeUrl: editor.ui.mapUrl(iframeUrl),
									editor: editor,
									className: "edui-for-" + cmd,
									title: title,
									holdScroll: cmd === "insertimage",
									fullscreen: /preview/.test(cmd),
									closeDialog: editor.getLang("closeDialog")
								}, type === "ok" ? {
									buttons: [{
										className: "edui-okbutton",
										label: editor.getLang("ok"),
										editor: editor,
										onclick: function() {
											dialog.close(true)
										}
									}, {
										className: "edui-cancelbutton",
										label: editor.getLang("cancel"),
										editor: editor,
										onclick: function() {
											dialog.close(false)
										}
									}]
								} : {}));
								editor.ui._dialogs[cmd + "Dialog"] = dialog
							}
							var ui = new editorui.Button({
								className: "edui-for-" + cmd,
								title: title,
								onclick: function() {
									if (editor.options.toolbarCallback) {
										if (true === editor.options.toolbarCallback(cmd,
												editor)) {
											return
										}
									}
									if (dialog) {
										switch (cmd) {
											case "wordimage":
												var images = editor.execCommand(
													"wordimage");
												if (images && images.length) {
													dialog.render();
													dialog.open()
												}
												break;
											case "scrawl":
												if (editor.queryCommandState(
													"scrawl") !== -1) {
													dialog.render();
													dialog.open()
												}
												break;
											default:
												dialog.render();
												dialog.open()
										}
									}
								},
								theme: editor.options.theme,
								disabled: cmd === "scrawl" && editor.queryCommandState(
									"scrawl") === -1
							});
							switch (cmd) {
								case "insertimage":
								case "formula":
									ui.shouldUiShow = function(cmd) {
										return function() {
											let closedNode = editor.selection.getRange()
												.getClosedNode();
											if (!closedNode || closedNode.tagName !==
												"IMG") {
												return false
											}
											if ("formula" === cmd && closedNode
												.getAttribute("data-formula-image") !== null
												) {
												return true
											}
											if ("insertimage" === cmd) {
												return true
											}
											return false
										}
									}(cmd);
									break
							}
							editorui.buttons[cmd] = ui;
							editor.addListener("selectionchange", function() {
								var unNeedCheckState = {
									edittable: 1
								};
								if (cmd in unNeedCheckState) return;
								var state = editor.queryCommandState(cmd);
								if (ui.getDom()) {
									ui.setDisabled(state === -1);
									ui.setChecked(state)
								}
							});
							return ui
						}
					})(ci.toLowerCase())
				}
			})(p, dialogBtns[p])
		}
		editorui.insertcode = function(editor, list, title) {
			list = editor.options["insertcode"] || [];
			title = editor.options.labelMap["insertcode"] || editor.getLang("labelMap.insertcode") || "";
			var items = [];
			utils.each(list, function(key, val) {
				items.push({
					label: key,
					value: val,
					theme: editor.options.theme,
					renderLabelHtml: function() {
						return '<div class="edui-label %%-label" >' + (this.label ||
							"") + "</div>"
					}
				})
			});
			var ui = new editorui.Combox({
				editor: editor,
				items: items,
				onselect: function(t, index) {
					editor.execCommand("insertcode", this.items[index].value)
				},
				onbuttonclick: function() {
					this.showPopup()
				},
				title: title,
				initValue: title,
				className: "edui-for-insertcode",
				indexByValue: function(value) {
					if (value) {
						for (var i = 0, ci; ci = this.items[i]; i++) {
							if (ci.value.indexOf(value) != -1) return i
						}
					}
					return -1
				}
			});
			editorui.buttons["insertcode"] = ui;
			editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
				if (!uiReady) {
					var state = editor.queryCommandState("insertcode");
					if (state == -1) {
						ui.setDisabled(true)
					} else {
						ui.setDisabled(false);
						var value = editor.queryCommandValue("insertcode");
						if (!value) {
							ui.setValue(title);
							return
						}
						value && (value = value.replace(/['"]/g, "").split(",")[0]);
						ui.setValue(value)
					}
				}
			});
			return ui
		};
		editorui.fontfamily = function(editor, list, title) {
			list = editor.options["fontfamily"] || [];
			title = editor.options.labelMap["fontfamily"] || editor.getLang("labelMap.fontfamily") || "";
			if (!list.length) return;
			for (var i = 0, ci, items = []; ci = list[i]; i++) {
				var langLabel = editor.getLang("fontfamily")[ci.name] || "";
				(function(key, val) {
					items.push({
						label: key,
						value: val,
						theme: editor.options.theme,
						renderLabelHtml: function() {
							return '<div class="edui-label %%-label" style="font-family:' +
								utils.unhtml(this.value) + '">' + (this.label || "") +
								"</div>"
						}
					})
				})(ci.label || langLabel, ci.val)
			}
			var ui = new editorui.Combox({
				editor: editor,
				items: items,
				onselect: function(t, index) {
					editor.execCommand("FontFamily", this.items[index].value)
				},
				onbuttonclick: function() {
					this.showPopup()
				},
				title: title,
				initValue: title,
				className: "edui-for-fontfamily",
				indexByValue: function(value) {
					if (value) {
						for (var i = 0, ci; ci = this.items[i]; i++) {
							if (ci.value.indexOf(value) != -1) return i
						}
					}
					return -1
				}
			});
			editorui.buttons["fontfamily"] = ui;
			editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
				if (!uiReady) {
					var state = editor.queryCommandState("FontFamily");
					if (state == -1) {
						ui.setDisabled(true)
					} else {
						ui.setDisabled(false);
						var value = editor.queryCommandValue("FontFamily");
						value && (value = value.replace(/['"]/g, "").split(",")[0]);
						ui.setValue(value)
					}
				}
			});
			return ui
		};
		editorui.fontsize = function(editor, list, title) {
			title = editor.options.labelMap["fontsize"] || editor.getLang("labelMap.fontsize") || "";
			list = list || editor.options["fontsize"] || [];
			if (!list.length) return;
			var items = [];
			for (var i = 0; i < list.length; i++) {
				var size = list[i] + "px";
				items.push({
					label: size,
					value: size,
					theme: editor.options.theme,
					renderLabelHtml: function() {
						return '<div class="edui-label %%-label" style="line-height:1;font-size:' +
							this.value + '">' + (this.label || "") + "</div>"
					}
				})
			}
			var ui = new editorui.Combox({
				editor: editor,
				items: items,
				title: title,
				initValue: title,
				onselect: function(t, index) {
					editor.execCommand("FontSize", this.items[index].value)
				},
				onbuttonclick: function() {
					this.showPopup()
				},
				className: "edui-for-fontsize"
			});
			editorui.buttons["fontsize"] = ui;
			editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
				if (!uiReady) {
					var state = editor.queryCommandState("FontSize");
					if (state == -1) {
						ui.setDisabled(true)
					} else {
						ui.setDisabled(false);
						ui.setValue(editor.queryCommandValue("FontSize"))
					}
				}
			});
			return ui
		};
		editorui.paragraph = function(editor, list, title) {
			title = editor.options.labelMap["paragraph"] || editor.getLang("labelMap.paragraph") || "";
			list = editor.options["paragraph"] || [];
			if (utils.isEmptyObject(list)) return;
			var items = [];
			for (var i in list) {
				items.push({
					value: i,
					label: list[i] || editor.getLang("paragraph")[i],
					theme: editor.options.theme,
					renderLabelHtml: function() {
						return '<div class="edui-label %%-label"><span class="edui-for-' + this
							.value + '">' + (this.label || "") + "</span></div>"
					}
				})
			}
			var ui = new editorui.Combox({
				editor: editor,
				items: items,
				title: title,
				initValue: title,
				className: "edui-for-paragraph",
				onselect: function(t, index) {
					editor.execCommand("Paragraph", this.items[index].value)
				},
				onbuttonclick: function() {
					this.showPopup()
				}
			});
			editorui.buttons["paragraph"] = ui;
			editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
				if (!uiReady) {
					var state = editor.queryCommandState("Paragraph");
					if (state == -1) {
						ui.setDisabled(true)
					} else {
						ui.setDisabled(false);
						var value = editor.queryCommandValue("Paragraph");
						var index = ui.indexByValue(value);
						if (index != -1) {
							ui.setValue(value)
						} else {
							ui.setValue(ui.initValue)
						}
					}
				}
			});
			return ui
		};
		editorui.customstyle = function(editor) {
			var list = editor.options["customstyle"] || [],
				title = editor.options.labelMap["customstyle"] || editor.getLang("labelMap.customstyle") ||
				"";
			if (!list.length) return;
			var langCs = editor.getLang("customstyle");
			for (var i = 0, items = [], t; t = list[i++];) {
				(function(t) {
					var ck = {};
					ck.label = t.label ? t.label : langCs[t.name];
					ck.style = t.style;
					ck.className = t.className;
					ck.tag = t.tag;
					items.push({
						label: ck.label,
						value: ck,
						theme: editor.options.theme,
						renderLabelHtml: function() {
							return '<div class="edui-label %%-label">' + "<" + ck.tag +
								" " + (ck.className ? ' class="' + ck.className + '"' :
								"") + (ck.style ? ' style="' + ck.style + '"' : "") + ">" +
								ck.label + "</" + ck.tag + ">" + "</div>"
						}
					})
				})(t)
			}
			var ui = new editorui.Combox({
				editor: editor,
				items: items,
				title: title,
				initValue: title,
				className: "edui-for-customstyle",
				onselect: function(t, index) {
					editor.execCommand("customstyle", this.items[index].value)
				},
				onbuttonclick: function() {
					this.showPopup()
				},
				indexByValue: function(value) {
					for (var i = 0, ti; ti = this.items[i++];) {
						if (ti.label == value) {
							return i - 1
						}
					}
					return -1
				}
			});
			editorui.buttons["customstyle"] = ui;
			editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
				if (!uiReady) {
					var state = editor.queryCommandState("customstyle");
					if (state == -1) {
						ui.setDisabled(true)
					} else {
						ui.setDisabled(false);
						var value = editor.queryCommandValue("customstyle");
						var index = ui.indexByValue(value);
						if (index != -1) {
							ui.setValue(value)
						} else {
							ui.setValue(ui.initValue)
						}
					}
				}
			});
			return ui
		};
		editorui.inserttable = function(editor, iframeUrl, title) {
			title = editor.options.labelMap["inserttable"] || editor.getLang("labelMap.inserttable") || "";
			var ui = new editorui.TableButton({
				editor: editor,
				title: title,
				className: "edui-for-inserttable",
				onpicktable: function(t, numCols, numRows) {
					editor.execCommand("InsertTable", {
						numRows: numRows,
						numCols: numCols,
						border: 1
					})
				},
				onbuttonclick: function() {
					this.showPopup()
				}
			});
			editorui.buttons["inserttable"] = ui;
			editor.addListener("selectionchange", function() {
				ui.setDisabled(editor.queryCommandState("inserttable") == -1)
			});
			return ui
		};
		editorui.lineheight = function(editor) {
			var val = editor.options.lineheight || [];
			if (!val.length) return;
			for (var i = 0, ci, items = []; ci = val[i++];) {
				items.push({
					label: ci,
					value: ci,
					theme: editor.options.theme,
					onclick: function() {
						editor.execCommand("lineheight", this.value)
					}
				})
			}
			var ui = new editorui.MenuButton({
				editor: editor,
				className: "edui-for-lineheight",
				title: editor.options.labelMap["lineheight"] || editor.getLang(
					"labelMap.lineheight") || "",
				items: items,
				onbuttonclick: function() {
					var value = editor.queryCommandValue("LineHeight") || this.value;
					editor.execCommand("LineHeight", value)
				}
			});
			editorui.buttons["lineheight"] = ui;
			editor.addListener("selectionchange", function() {
				var state = editor.queryCommandState("LineHeight");
				if (state == -1) {
					ui.setDisabled(true)
				} else {
					ui.setDisabled(false);
					var value = editor.queryCommandValue("LineHeight");
					value && ui.setValue((value + "").replace(/cm/, ""));
					ui.setChecked(state)
				}
			});
			return ui
		};
		var rowspacings = ["top", "bottom"];
		for (var r = 0, ri; ri = rowspacings[r++];) {
			(function(cmd) {
				editorui["rowspacing" + cmd] = function(editor) {
					var val = editor.options["rowspacing" + cmd] || [];
					if (!val.length) return null;
					for (var i = 0, ci, items = []; ci = val[i++];) {
						items.push({
							label: ci,
							value: ci,
							theme: editor.options.theme,
							onclick: function() {
								editor.execCommand("rowspacing", this.value, cmd)
							}
						})
					}
					var ui = new editorui.MenuButton({
						editor: editor,
						className: "edui-for-rowspacing" + cmd,
						title: editor.options.labelMap["rowspacing" + cmd] || editor.getLang(
							"labelMap.rowspacing" + cmd) || "",
						items: items,
						onbuttonclick: function() {
							var value = editor.queryCommandValue("rowspacing", cmd) || this
								.value;
							editor.execCommand("rowspacing", value, cmd)
						}
					});
					editorui.buttons[cmd] = ui;
					editor.addListener("selectionchange", function() {
						var state = editor.queryCommandState("rowspacing", cmd);
						if (state == -1) {
							ui.setDisabled(true)
						} else {
							ui.setDisabled(false);
							var value = editor.queryCommandValue("rowspacing", cmd);
							value && ui.setValue((value + "").replace(/%/, ""));
							ui.setChecked(state)
						}
					});
					return ui
				}
			})(ri)
		}
		var lists = ["insertorderedlist", "insertunorderedlist"];
		for (var l = 0, cl; cl = lists[l++];) {
			(function(cmd) {
				editorui[cmd] = function(editor) {
					var vals = editor.options[cmd],
						_onMenuClick = function() {
							editor.execCommand(cmd, this.value)
						},
						items = [];
					for (var i in vals) {
						items.push({
							label: vals[i] || editor.getLang()[cmd][i] || "",
							value: i,
							theme: editor.options.theme,
							onclick: _onMenuClick
						})
					}
					var ui = new editorui.MenuButton({
						editor: editor,
						className: "edui-for-" + cmd,
						title: editor.getLang("labelMap." + cmd) || "",
						items: items,
						onbuttonclick: function() {
							var value = editor.queryCommandValue(cmd) || this.value;
							editor.execCommand(cmd, value)
						}
					});
					editorui.buttons[cmd] = ui;
					editor.addListener("selectionchange", function() {
						var state = editor.queryCommandState(cmd);
						if (state == -1) {
							ui.setDisabled(true)
						} else {
							ui.setDisabled(false);
							var value = editor.queryCommandValue(cmd);
							ui.setValue(value);
							ui.setChecked(state)
						}
					});
					return ui
				}
			})(cl)
		}
		editorui.fullscreen = function(editor, title) {
			title = editor.options.labelMap["fullscreen"] || editor.getLang("labelMap.fullscreen") || "";
			var ui = new editorui.Button({
				className: "edui-for-fullscreen",
				title: title,
				theme: editor.options.theme,
				onclick: function() {
					if (editor.ui) {
						editor.ui.setFullScreen(!editor.ui.isFullScreen())
					}
					this.setChecked(editor.ui.isFullScreen())
				}
			});
			editorui.buttons["fullscreen"] = ui;
			editor.addListener("selectionchange", function() {
				var state = editor.queryCommandState("fullscreen");
				ui.setDisabled(state == -1);
				ui.setChecked(editor.ui.isFullScreen())
			});
			return ui
		};
		editorui["emotion"] = function(editor, iframeUrl) {
			var cmd = "emotion";
			var ui = new editorui.MultiMenuPop({
				title: editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd + "") || "",
				editor: editor,
				className: "edui-for-" + cmd,
				iframeUrl: editor.ui.mapUrl(iframeUrl || (editor.options.dialogIframeUrlMap || {})[
					cmd] || dialogIframeUrlMap[cmd])
			});
			editorui.buttons[cmd] = ui;
			editor.addListener("selectionchange", function() {
				ui.setDisabled(editor.queryCommandState(cmd) == -1)
			});
			return ui
		};
		editorui["autotypeset"] = function(editor) {
			var ui = new editorui.AutoTypeSetButton({
				editor: editor,
				title: editor.options.labelMap["autotypeset"] || editor.getLang(
					"labelMap.autotypeset") || "",
				className: "edui-for-autotypeset",
				onbuttonclick: function() {
					editor.execCommand("autotypeset")
				}
			});
			editorui.buttons["autotypeset"] = ui;
			editor.addListener("selectionchange", function() {
				ui.setDisabled(editor.queryCommandState("autotypeset") == -1)
			});
			return ui
		};
		editorui["simpleupload"] = function(editor) {
			var name = "simpleupload",
				ui = new editorui.Button({
					className: "edui-for-" + name,
					title: editor.options.labelMap[name] || editor.getLang("labelMap." + name) || "",
					onclick: function() {},
					theme: editor.options.theme,
					showText: false
				});
			editorui.buttons[name] = ui;
			editor.addListener("ready", function() {
				var b = ui.getDom("body"),
					iconSpan = b.children[0];
				editor.fireEvent("simpleuploadbtnready", iconSpan)
			});
			editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
				var state = editor.queryCommandState(name);
				if (state == -1) {
					ui.setDisabled(true);
					ui.setChecked(false)
				} else {
					if (!uiReady) {
						ui.setDisabled(false);
						ui.setChecked(state)
					}
				}
			});
			return ui
		}
	})();
	(function() {
		var utils = baidu.editor.utils,
			uiUtils = baidu.editor.ui.uiUtils,
			UIBase = baidu.editor.ui.UIBase,
			domUtils = baidu.editor.dom.domUtils;
		var nodeStack = [];

		function EditorUI(options) {
			this.initOptions(options);
			this.initEditorUI()
		}
		EditorUI.prototype = {
			uiName: "editor",
			initEditorUI: function() {
				this.editor.ui = this;
				this._dialogs = {};
				this.initUIBase();
				this._initToolbars();
				var editor = this.editor,
					me = this;
				editor.addListener("ready", function() {
					editor.getDialog = function(name) {
						return editor.ui._dialogs[name + "Dialog"]
					};
					domUtils.on(editor.window, "scroll", function(evt) {
						baidu.editor.ui.Popup.postHide(evt)
					});
					editor.ui._actualFrameWidth = editor.options.initialFrameWidth;
					UE.browser.ie && UE.browser.version === 6 && editor.container.ownerDocument
						.execCommand("BackgroundImageCache", false, true);
					if (editor.options.elementPathEnabled) {
						editor.ui.getDom("elementpath").innerHTML =
							'<div class="edui-editor-breadcrumb">' + editor.getLang(
								"elementPathTip") + ":</div>"
					}
					if (editor.options.wordCount) {
						function countFn() {
							setCount(editor, me);
							domUtils.un(editor.document, "click", arguments.callee)
						}
						domUtils.on(editor.document, "click", countFn);
						editor.ui.getDom("wordcount").innerHTML = editor.getLang("wordCountTip")
					}
					editor.ui._scale();
					if (editor.options.scaleEnabled) {
						if (editor.autoHeightEnabled) {
							editor.disableAutoHeight()
						}
						me.enableScale()
					} else {
						me.disableScale()
					}
					if (!editor.options.elementPathEnabled && !editor.options.wordCount && !
						editor.options.scaleEnabled) {
						editor.ui.getDom("elementpath").style.display = "none";
						editor.ui.getDom("wordcount").style.display = "none";
						editor.ui.getDom("scale").style.display = "none"
					}
					if (!editor.selection.isFocus()) return;
					editor.fireEvent("selectionchange", false, true)
				});
				editor.addListener("mousedown", function(t, evt) {
					var el = evt.target || evt.srcElement;
					baidu.editor.ui.Popup.postHide(evt, el);
					baidu.editor.ui.ShortCutMenu.postHide(evt)
				});
				editor.addListener("delcells", function() {
					if (UE.ui["edittip"]) {
						new UE.ui["edittip"](editor)
					}
					editor.getDialog("edittip").open()
				});
				var pastePop, isPaste = false,
					timer;
				editor.addListener("afterpaste", function() {
					if (editor.queryCommandState("pasteplain")) return;
					if (baidu.editor.ui.PastePicker) {
						pastePop = new baidu.editor.ui.Popup({
							content: new baidu.editor.ui.PastePicker({
								editor: editor
							}),
							editor: editor,
							className: "edui-wordpastepop"
						});
						pastePop.render()
					}
					isPaste = true
				});
				editor.addListener("afterinserthtml", function() {
					clearTimeout(timer);
					timer = setTimeout(function() {
						if (pastePop && (isPaste || editor.ui._isTransfer)) {
							if (pastePop.isHidden()) {
								var span = domUtils.createElement(editor.document,
										"span", {
											style: "line-height:0px;",
											innerHTML: "\ufeff"
										}),
									range = editor.selection.getRange();
								range.insertNode(span);
								var tmp = getDomNode(span, "firstChild",
									"previousSibling");
								tmp && pastePop.showAnchor(tmp.nodeType == 3 ? tmp
									.parentNode : tmp);
								domUtils.remove(span)
							} else {
								pastePop.show()
							}
							delete editor.ui._isTransfer;
							isPaste = false
						}
					}, 200)
				});
				editor.addListener("contextmenu", function(t, evt) {
					baidu.editor.ui.Popup.postHide(evt)
				});
				editor.addListener("keydown", function(t, evt) {
					if (pastePop) pastePop.dispose(evt);
					var keyCode = evt.keyCode || evt.which;
					if (evt.altKey && keyCode == 90) {
						UE.ui.buttons["fullscreen"].onclick()
					}
				});
				editor.addListener("wordcount", function(type) {
					setCount(this, me)
				});

				function setCount(editor, ui) {
					editor.setOpt({
						wordCount: true,
						maximumWords: 1e4,
						wordCountMsg: editor.options.wordCountMsg || editor.getLang(
							"wordCountMsg"),
						wordOverFlowMsg: editor.options.wordOverFlowMsg || editor.getLang(
							"wordOverFlowMsg")
					});
					var opt = editor.options,
						max = opt.maximumWords,
						msg = opt.wordCountMsg,
						errMsg = opt.wordOverFlowMsg,
						countDom = ui.getDom("wordcount");
					if (!opt.wordCount) {
						return
					}
					var count = editor.getContentLength(true);
					if (count > max) {
						countDom.innerHTML = errMsg;
						editor.fireEvent("wordcountoverflow")
					} else {
						countDom.innerHTML = msg.replace("{#leave}", max - count).replace("{#count}",
							count)
					}
				}
				editor.addListener("selectionchange", function() {
					if (editor.options.elementPathEnabled) {
						me[(editor.queryCommandState("elementpath") == -1 ? "dis" : "en") +
							"ableElementPath"]()
					}
					if (editor.options.scaleEnabled) {
						me[(editor.queryCommandState("scale") == -1 ? "dis" : "en") +
							"ableScale"]()
					}
				});
				var popup = new baidu.editor.ui.Popup({
					editor: editor,
					content: "",
					className: "edui-bubble",
					_onEditButtonClick: function() {
						this.hide();
						editor.ui._dialogs.linkDialog.open()
					},
					_onImgEditButtonClick: function(name) {
						this.hide();
						editor.ui._dialogs[name] && editor.ui._dialogs[name].open()
					},
					_onImgSetFloat: function(value) {
						this.hide();
						editor.execCommand("imagefloat", value)
					},
					_setIframeAlign: function(value) {
						var frame = popup.anchorEl;
						var newFrame = frame.cloneNode(true);
						switch (value) {
							case -2:
								newFrame.setAttribute("align", "");
								break;
							case -1:
								newFrame.setAttribute("align", "left");
								break;
							case 1:
								newFrame.setAttribute("align", "right");
								break
						}
						frame.parentNode.insertBefore(newFrame, frame);
						domUtils.remove(frame);
						popup.anchorEl = newFrame;
						popup.showAnchor(popup.anchorEl)
					},
					_updateIframe: function() {
						var frame = editor._iframe = popup.anchorEl;
						if (domUtils.hasClass(frame, "ueditor_baidumap")) {
							editor.selection.getRange().selectNode(frame).select();
							editor.ui._dialogs.mapDialog.open();
							popup.hide()
						} else {
							editor.ui._dialogs.insertframeDialog.open();
							popup.hide()
						}
					},
					_onRemoveButtonClick: function(cmdName) {
						editor.execCommand(cmdName);
						this.hide()
					},
					queryAutoHide: function(el) {
						if (el && el.ownerDocument == editor.document) {
							if (el.tagName.toLowerCase() == "img" || domUtils
								.findParentByTagName(el, "a", true)) {
								return el !== popup.anchorEl
							}
						}
						return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el)
					}
				});
				popup.render();
				if (editor.options.imagePopup) {
					editor.addListener("mouseover", function(t, evt) {
						evt = evt || window.event;
						var el = evt.target || evt.srcElement;
						if (editor.ui._dialogs.insertframeDialog && /iframe/gi.test(el
							.tagName)) {
							var html = popup.formatHtml("<nobr>" +
								'<span onclick=$$._setIframeAlign(-2) class="edui-clickable">' +
								editor.getLang("default") +
								'</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(-1) class="edui-clickable">' +
								editor.getLang("justifyleft") +
								'</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(1) class="edui-clickable">' +
								editor.getLang("justifyright") + "</span>&nbsp;&nbsp;" +
								' <span onclick="$$._updateIframe( this);" class="edui-clickable">' +
								editor.getLang("modify") + "</span></nobr>");
							if (html) {
								popup.getDom("content").innerHTML = html;
								popup.anchorEl = el;
								popup.showAnchor(popup.anchorEl)
							} else {
								popup.hide()
							}
						}
					});
					editor.addListener("selectionchange", function(t, causeByUi) {
						if (!causeByUi) {
							return
						}
						var html = "",
							str = "",
							closedNode = editor.selection.getRange().getClosedNode(),
							dialogs = editor.ui._dialogs;
						if (closedNode && closedNode.tagName === "IMG") {
							var dialogName = "insertimageDialog";
							if (closedNode.className.indexOf("edui-faked-video") !== -1 ||
								closedNode.className.indexOf("edui-upload-video") !== -1) {
								dialogName = "insertvideoDialog"
							}
							if (closedNode.className.indexOf("edui-faked-audio") !== -1 ||
								closedNode.className.indexOf("edui-upload-audio") !== -1) {
								dialogName = "insertaudioDialog"
							}
							if (closedNode.getAttribute("anchorname")) {
								dialogName = "anchorDialog";
								html = popup.formatHtml("<nobr>" +
									'<span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">' +
									editor.getLang("modify") + "</span>&nbsp;&nbsp;" +
									"<span onclick=$$._onRemoveButtonClick('anchor') class=\"edui-clickable\">" +
									editor.getLang("delete") + "</span></nobr>")
							}
							if (domUtils.hasClass(closedNode, "uep-loading") || domUtils
								.hasClass(closedNode, "uep-loading-error")) {
								dialogName = ""
							}
							if (!dialogs[dialogName]) {
								return
							}
							var actions = [];
							if (closedNode.getAttribute("data-word-image")) {
								actions.push(
									"<span onclick=\"$$._onImgEditButtonClick('wordimageDialog');\" class='edui-clickable edui-popup-action-item'>" +
									editor.getLang("save") + "</span>")
							} else {}
							if (actions.length > 0) {
								actions.unshift("<nobr>");
								actions.push("</nobr>")
							}!html && (html = popup.formatHtml(actions.join("")))
						}
						if (editor.ui._dialogs.linkDialog) {
							var link = editor.queryCommandValue("link");
							var url;
							if (link && (url = link.getAttribute("_href") || link.getAttribute(
									"href", 2))) {
								var txt = url;
								if (url.length > 30) {
									txt = url.substring(0, 20) + "..."
								}
								if (html) {
									html += '<div style="height:5px;"></div>'
								}
								html += popup.formatHtml("<nobr>" + editor.getLang(
									"anchorMsg") + ': <a target="_blank" href="' + url +
									'" title="' + url + '" >' + txt + "</a>" +
									' <span class="edui-clickable" onclick="$$._onEditButtonClick();">' +
									editor.getLang("modify") + "</span>" +
									' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> ' +
									editor.getLang("clear") + "</span></nobr>");
								popup.showAnchor(link)
							}
						}
						if (html) {
							popup.getDom("content").innerHTML = html;
							popup.anchorEl = closedNode || link;
							popup.showAnchor(popup.anchorEl)
						} else {
							popup.hide()
						}
					})
				}
			},
			_initToolbars: function() {
				var editor = this.editor;
				var toolbars = this.toolbars || [];
				if (toolbars[0]) {
					toolbars[0].unshift("message")
				}
				var toolbarUis = [];
				var extraUIs = [];
				for (var i = 0; i < toolbars.length; i++) {
					var toolbar = toolbars[i];
					var toolbarUi = new baidu.editor.ui.Toolbar({
						theme: editor.options.theme
					});
					for (var j = 0; j < toolbar.length; j++) {
						var toolbarItem = toolbar[j];
						var toolbarItemUi = null;
						if (typeof toolbarItem == "string") {
							toolbarItem = toolbarItem.toLowerCase();
							if (toolbarItem === "|") {
								toolbarItem = "Separator"
							}
							if (toolbarItem === "||") {
								toolbarItem = "Breakline"
							}
							var ui = baidu.editor.ui[toolbarItem];
							if (ui) {
								if (utils.isFunction(ui)) {
									toolbarItemUi = new baidu.editor.ui[toolbarItem](editor)
								} else {
									if (ui.id && ui.id !== editor.key) {
										continue
									}
									var itemUI = ui.execFn.call(editor, editor, toolbarItem);
									if (itemUI) {
										if (ui.index === undefined) {
											toolbarUi.add(itemUI);
											continue
										} else {
											extraUIs.push({
												index: ui.index,
												itemUI: itemUI
											})
										}
									}
								}
							}
							if (toolbarItem === "fullscreen") {
								if (toolbarUis && toolbarUis[0]) {
									toolbarUis[0].items.splice(0, 0, toolbarItemUi)
								} else {
									toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi)
								}
								continue
							}
						} else {
							toolbarItemUi = toolbarItem
						}
						if (toolbarItemUi && toolbarItemUi.id) {
							toolbarUi.add(toolbarItemUi)
						}
					}
					toolbarUis[i] = toolbarUi
				}
				utils.each(extraUIs, function(obj) {
					toolbarUi.add(obj.itemUI, obj.index)
				});
				this.toolbars = toolbarUis
			},
			getHtmlTpl: function() {
				return '<div id="##" class="%%">' + '<div id="##_toolbarbox" class="%%-toolbarbox">' + (
						this.toolbars.length ?
						'<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
						this.renderToolbarBoxHtml() + "</div></div>" : "") +
					'<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
					'<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">' +
					this.editor.getLang("clickToUpload") + "</div>" +
					'<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
					'<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
					'<div style="height:0;overflow:hidden;clear:both;"></div>' + "</div>" +
					'<div id="##_message_holder" class="%%-messageholder"></div>' + "</div>" +
					'<div id="##_iframeholder" class="%%-iframeholder">' + "</div>" +
					'<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
					'<td id="##_elementpath" class="%%-bottombar"></td>' +
					'<td id="##_wordcount" class="%%-wordcount"></td>' +
					'<td id="##_scale" class="%%-scale"><div class="%%-icon"></div></td>' +
					"</tr></table></div>" + '<div id="##_scalelayer"></div>' + "</div>"
			},
			showWordImageDialog: function() {
				this._dialogs["wordimageDialog"].open()
			},
			renderToolbarBoxHtml: function() {
				var buff = [];
				for (var i = 0; i < this.toolbars.length; i++) {
					buff.push(this.toolbars[i].renderHtml())
				}
				return buff.join("")
			},
			setFullScreen: function(fullscreen) {
				var editor = this.editor,
					container = editor.container.parentNode.parentNode;
				if (this._fullscreen != fullscreen) {
					this._fullscreen = fullscreen;
					this.editor.fireEvent("beforefullscreenchange", fullscreen);
					if (baidu.editor.browser.gecko) {
						var bk = editor.selection.getRange().createBookmark()
					}
					if (fullscreen) {
						this._bakEditorContaninerWidth = editor.iframe.parentNode.style.width;
						while (container.tagName !== "BODY") {
							var position = baidu.editor.dom.domUtils.getComputedStyle(container,
								"position");
							nodeStack.push(position);
							container.style.position = "static";
							container = container.parentNode
						}
						this._bakHtmlOverflow = document.documentElement.style.overflow;
						this._bakBodyOverflow = document.body.style.overflow;
						this._bakAutoHeight = this.editor.autoHeightEnabled;
						this._bakScrollTop = Math.max(document.documentElement.scrollTop, document.body
							.scrollTop);
						if (this._bakAutoHeight) {
							editor.autoHeightEnabled = false;
							this.editor.disableAutoHeight()
						}
						document.documentElement.style.overflow = "hidden";
						window.scrollTo(0, window.scrollY);
						this._bakCssText = this.getDom().style.cssText;
						this._bakCssText1 = this.getDom("iframeholder").style.cssText;
						editor.iframe.parentNode.style.width = "";
						this._updateFullScreen()
					} else {
						while (container.tagName !== "BODY") {
							container.style.position = nodeStack.shift();
							container = container.parentNode
						}
						this.getDom().style.cssText = this._bakCssText;
						this.getDom("iframeholder").style.cssText = this._bakCssText1;
						if (this._bakAutoHeight) {
							editor.autoHeightEnabled = true;
							this.editor.enableAutoHeight()
						}
						document.documentElement.style.overflow = this._bakHtmlOverflow;
						document.body.style.overflow = this._bakBodyOverflow;
						editor.iframe.parentNode.style.width = this._bakEditorContaninerWidth;
						window.scrollTo(0, this._bakScrollTop)
					}
					if (browser.gecko && editor.body.contentEditable === "true") {
						var input = document.createElement("input");
						document.body.appendChild(input);
						editor.body.contentEditable = false;
						setTimeout(function() {
							input.focus();
							setTimeout(function() {
								editor.body.contentEditable = true;
								editor.fireEvent("fullscreenchanged", fullscreen);
								editor.selection.getRange().moveToBookmark(bk).select(
									true);
								baidu.editor.dom.domUtils.remove(input);
								fullscreen && window.scroll(0, 0)
							}, 0)
						}, 0)
					}
					if (editor.body.contentEditable === "true") {
						this.editor.fireEvent("fullscreenchanged", fullscreen);
						this.triggerLayout()
					}
				}
			},
			_updateFullScreen: function() {
				if (this._fullscreen) {
					var vpRect = uiUtils.getViewportRect();
					this.getDom().style.cssText =
						"border:0;position:absolute;left:0;top:var(--ueditor-top-offset," + (this.editor
							.options.topOffset || 0) + "px);width:" + vpRect.width + "px;height:" +
						vpRect.height + "px;z-index:" + (this.getDom().style.zIndex * 1 + 100);
					uiUtils.setViewportOffset(this.getDom(), {
						left: 0
					});
					this.editor.setHeight(vpRect.height - this.getDom("toolbarbox").offsetHeight - this
						.getDom("bottombar").offsetHeight - (this.editor.options.topOffset || 0),
						true);
					if (browser.gecko) {
						try {
							window.onresize()
						} catch (e) {}
					}
				}
			},
			_updateElementPath: function() {
				var bottom = this.getDom("elementpath"),
					list;
				if (this.elementPathEnabled && (list = this.editor.queryCommandValue("elementpath"))) {
					var buff = [];
					for (var i = 0, ci; ci = list[i]; i++) {
						buff[i] = this.formatHtml(
							'<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' +
							i + '&quot;);">' + ci + "</span>")
					}
					bottom.innerHTML =
						'<div class="edui-editor-breadcrumb" onmousedown="return false;">' + this.editor
						.getLang("elementPathTip") + ": " + buff.join(" &gt; ") + "</div>"
				} else {
					bottom.style.display = "none"
				}
			},
			disableElementPath: function() {
				var bottom = this.getDom("elementpath");
				bottom.innerHTML = "";
				bottom.style.display = "none";
				this.elementPathEnabled = false
			},
			enableElementPath: function() {
				var bottom = this.getDom("elementpath");
				bottom.style.display = "";
				this.elementPathEnabled = true;
				this._updateElementPath()
			},
			_scale: function() {
				var doc = document,
					editor = this.editor,
					editorHolder = editor.container,
					editorDocument = editor.document,
					toolbarBox = this.getDom("toolbarbox"),
					bottombar = this.getDom("bottombar"),
					scale = this.getDom("scale"),
					scalelayer = this.getDom("scalelayer");
				var isMouseMove = false,
					position = null,
					minEditorHeight = 0,
					minEditorWidth = editor.options.minFrameWidth,
					pageX = 0,
					pageY = 0,
					scaleWidth = 0,
					scaleHeight = 0;

				function down() {
					position = domUtils.getXY(editorHolder);
					if (!minEditorHeight) {
						minEditorHeight = editor.options.minFrameHeight + toolbarBox.offsetHeight +
							bottombar.offsetHeight
					}
					scalelayer.style.cssText =
						"position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:" +
						editorHolder.offsetWidth + "px;height:" + editorHolder.offsetHeight +
						"px;z-index:" + (editor.options.zIndex + 1);
					domUtils.on(doc, "mousemove", move);
					domUtils.on(editorDocument, "mouseup", up);
					domUtils.on(doc, "mouseup", up)
				}
				var me = this;
				this.editor.addListener("fullscreenchanged", function(e, fullScreen) {
					if (fullScreen) {
						me.disableScale()
					} else {
						if (me.editor.options.scaleEnabled) {
							me.enableScale();
							var tmpNode = me.editor.document.createElement("span");
							me.editor.body.appendChild(tmpNode);
							me.editor.body.style.height = Math.max(domUtils.getXY(tmpNode).y, me
								.editor.iframe.offsetHeight - 20) + "px";
							domUtils.remove(tmpNode)
						}
					}
				});

				function move(event) {
					clearSelection();
					var e = event || window.event;
					pageX = e.pageX || doc.documentElement.scrollLeft + e.clientX;
					pageY = e.pageY || doc.documentElement.scrollTop + e.clientY;
					scaleWidth = pageX - position.x;
					scaleHeight = pageY - position.y;
					if (scaleWidth >= minEditorWidth) {
						isMouseMove = true;
						scalelayer.style.width = scaleWidth + "px"
					}
					if (scaleHeight >= minEditorHeight) {
						isMouseMove = true;
						scalelayer.style.height = scaleHeight + "px"
					}
				}

				function up() {
					if (isMouseMove) {
						isMouseMove = false;
						editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2;
						editorHolder.style.width = editor.ui._actualFrameWidth + "px";
						editor.setHeight(scalelayer.offsetHeight - bottombar.offsetHeight - toolbarBox
							.offsetHeight - 2, true)
					}
					if (scalelayer) {
						scalelayer.style.display = "none"
					}
					clearSelection();
					domUtils.un(doc, "mousemove", move);
					domUtils.un(editorDocument, "mouseup", up);
					domUtils.un(doc, "mouseup", up)
				}

				function clearSelection() {
					if (browser.ie) doc.selection.clear();
					else window.getSelection().removeAllRanges()
				}
				this.enableScale = function() {
					if (editor.queryCommandState("source") == 1) return;
					scale.style.display = "";
					this.scaleEnabled = true;
					domUtils.on(scale, "mousedown", down)
				};
				this.disableScale = function() {
					scale.style.display = "none";
					this.scaleEnabled = false;
					domUtils.un(scale, "mousedown", down)
				}
			},
			isFullScreen: function() {
				return this._fullscreen
			},
			postRender: function() {
				UIBase.prototype.postRender.call(this);
				for (var i = 0; i < this.toolbars.length; i++) {
					this.toolbars[i].postRender()
				}
				var me = this;
				var timerId, domUtils = baidu.editor.dom.domUtils,
					updateFullScreenTime = function() {
						clearTimeout(timerId);
						timerId = setTimeout(function() {
							me._updateFullScreen()
						})
					};
				domUtils.on(window, "resize", updateFullScreenTime);
				me.addListener("destroy", function() {
					domUtils.un(window, "resize", updateFullScreenTime);
					clearTimeout(timerId)
				})
			},
			showToolbarMsg: function(msg, flag) {
				this.getDom("toolbarmsg_label").innerHTML = msg;
				this.getDom("toolbarmsg").style.display = "";
				if (!flag) {
					var w = this.getDom("upload_dialog");
					w.style.display = "none"
				}
			},
			hideToolbarMsg: function() {
				this.getDom("toolbarmsg").style.display = "none"
			},
			mapUrl: function(url) {
				return url ? url.replace("~/", this.editor.options.UEDITOR_CORS_URL || "") : ""
			},
			triggerLayout: function() {
				var dom = this.getDom();
				if (dom.style.zoom == "1") {
					dom.style.zoom = "100%"
				} else {
					dom.style.zoom = "1"
				}
			}
		};
		utils.inherits(EditorUI, baidu.editor.ui.UIBase);
		var instances = {};
		UE.ui.Editor = function(options) {
			var editor = new UE.Editor(options);
			editor.options.editor = editor;
			utils.loadFile(document, {
				href: editor.options.themePath + editor.options.theme + "/css/ueditor.css?98125a73",
				tag: "link",
				type: "text/css",
				rel: "stylesheet"
			});
			var oldRender = editor.render;
			editor.render = function(holder) {
				if (holder.constructor === String) {
					editor.key = holder;
					instances[holder] = editor
				}
				utils.domReady(function() {
					editor.langIsReady ? renderUI() : editor.addListener("langReady", renderUI);

					function renderUI() {
						editor.setOpt({
							labelMap: editor.options.labelMap || editor.getLang(
								"labelMap")
						});
						new EditorUI(editor.options);
						if (holder) {
							if (holder.constructor === String) {
								holder = document.getElementById(holder)
							}
							holder && holder.getAttribute("name") && (editor.options.textarea =
								holder.getAttribute("name"));
							if (holder && /script|textarea/gi.test(holder.tagName)) {
								var newDiv = document.createElement("div");
								holder.parentNode.insertBefore(newDiv, holder);
								var cont = holder.value || holder.innerHTML;
								editor.options.initialContent = /^[\t\r\n ]*$/.test(cont) ?
									editor.options.initialContent : cont.replace(
										/>[\n\r\t]+([ ]{4})+/g, ">").replace(
										/[\n\r\t]+([ ]{4})+</g, "<").replace(/>[\n\r\t]+</g,
										"><");
								holder.className && (newDiv.className = holder.className);
								holder.style.cssText && (newDiv.style.cssText = holder.style
									.cssText);
								if (/textarea/i.test(holder.tagName)) {
									editor.textarea = holder;
									editor.textarea.style.display = "none"
								} else {
									holder.parentNode.removeChild(holder)
								}
								if (holder.id) {
									newDiv.id = holder.id;
									domUtils.removeAttributes(holder, "id")
								}
								holder = newDiv;
								holder.innerHTML = ""
							}
						}
						domUtils.addClass(holder, "edui-" + editor.options.theme);
						editor.ui.render(holder);
						var opt = editor.options;
						editor.container = editor.ui.getDom();
						var parents = domUtils.findParents(holder, true);
						var displays = [];
						for (var i = 0, ci; ci = parents[i]; i++) {
							displays[i] = ci.style.display;
							ci.style.display = "block"
						}
						if (opt.initialFrameWidth) {
							opt.minFrameWidth = opt.initialFrameWidth
						} else {
							opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth;
							var styleWidth = holder.style.width;
							if (/%$/.test(styleWidth)) {
								opt.initialFrameWidth = styleWidth
							}
						}
						if (opt.initialFrameHeight) {
							opt.minFrameHeight = opt.initialFrameHeight
						} else {
							opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight
						}
						for (var i = 0, ci; ci = parents[i]; i++) {
							ci.style.display = displays[i]
						}
						if (holder.style.height) {
							holder.style.height = ""
						}
						editor.container.style.width = opt.initialFrameWidth + (/%$/.test(opt
							.initialFrameWidth) ? "" : "px");
						editor.container.style.zIndex = opt.zIndex;
						oldRender.call(editor, editor.ui.getDom("iframeholder"));
						editor.fireEvent("afteruiready")
					}
				})
			};
			return editor
		};
		UE.getEditor = function(id, opt) {
			var editor = instances[id];
			if (!editor) {
				editor = instances[id] = new UE.ui.Editor(opt);
				editor.render(id)
			}
			return editor
		};
		UE.delEditor = function(id) {
			var editor;
			if (editor = instances[id]) {
				editor.key && editor.destroy();
				delete instances[id]
			}
		};
		UE.registerUI = function(uiName, fn, index, editorId) {
			utils.each(uiName.split(/\s+/), function(name) {
				baidu.editor.ui[name] = {
					id: editorId,
					execFn: fn,
					index: index
				}
			})
		}
	})();
	UE.registerUI("message", function(editor) {
		var editorui = baidu.editor.ui;
		var Message = editorui.Message;
		var holder;
		var _messageItems = [];
		var me = editor;
		me.setOpt("enableMessageShow", true);
		if (me.getOpt("enableMessageShow") === false) {
			return
		}
		me.addListener("ready", function() {
			holder = document.getElementById(me.ui.id + "_message_holder");
			updateHolderPos();
			setTimeout(function() {
				updateHolderPos()
			}, 500)
		});
		me.addListener("showmessage", function(type, opt) {
			opt = utils.isString(opt) ? {
				content: opt
			} : opt;
			var message = new Message({
					timeout: opt.timeout,
					type: opt.type,
					content: opt.content,
					keepshow: opt.keepshow,
					editor: me
				}),
				mid = opt.id || "msg_" + (+new Date).toString(36);
			message.render(holder);
			_messageItems[mid] = message;
			message.reset(opt);
			updateHolderPos();
			return mid
		});
		me.addListener("updatemessage", function(type, id, opt) {
			opt = utils.isString(opt) ? {
				content: opt
			} : opt;
			var message = _messageItems[id];
			message.render(holder);
			message && message.reset(opt)
		});
		me.addListener("hidemessage", function(type, id) {
			var message = _messageItems[id];
			message && message.hide()
		});

		function updateHolderPos() {
			if (!holder || !me.ui) return;
			var toolbarbox = me.ui.getDom("toolbarbox");
			if (toolbarbox) {
				holder.style.top = toolbarbox.offsetHeight + 3 + "px"
			}
			holder.style.zIndex = Math.max(me.options.zIndex, me.iframe.style.zIndex) + 1
		}
	})
})();